Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions niri-config/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct Layout {
pub gaps: f64,
pub struts: Struts,
pub background_color: Color,
pub auto_tile: Option<AutoTile>,
}

impl Default for Layout {
Expand Down Expand Up @@ -52,6 +53,7 @@ impl Default for Layout {
PresetSize::Proportion(2. / 3.),
],
background_color: DEFAULT_BACKGROUND_COLOR,
auto_tile: None,
}
}
}
Expand Down Expand Up @@ -91,6 +93,10 @@ impl MergeWith<LayoutPart> for Layout {
if self.preset_window_heights.is_empty() {
self.preset_window_heights = Layout::default().preset_window_heights;
}

if let Some(x) = &part.auto_tile {
self.auto_tile = Some(x.clone());
}
}
}

Expand Down Expand Up @@ -126,6 +132,16 @@ pub struct LayoutPart {
pub struts: Option<Struts>,
#[knuffel(child)]
pub background_color: Option<Color>,
#[knuffel(child)]
pub auto_tile: Option<AutoTile>,
}

#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
pub struct AutoTile {
/// Maximum number of columns to auto-tile before scrolling kicks in.
/// Defaults to 2 (full screen, then 50/50, then scroll).
#[knuffel(child, unwrap(argument), default = 2)]
pub max_columns: u16,
}

#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
Expand Down
1 change: 1 addition & 0 deletions niri-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,7 @@ mod tests {
b: 0.25,
a: 1.0,
},
auto_tile: None,
},
prefer_no_csd: true,
cursor: Cursor {
Expand Down
69 changes: 69 additions & 0 deletions src/layout/scrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ pub struct ScrollingSpace<W: LayoutElement> {

/// Configurable properties of the layout.
options: Rc<Options>,

/// Number of columns that are currently auto-tiled (filling the screen with dwindle layout).
/// These are always the first N columns. Columns beyond this count are in scrolling mode.
auto_tile_count: usize,
}

niri_render_elements! {
Expand Down Expand Up @@ -306,6 +310,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
scale,
clock,
options,
auto_tile_count: 0,
}
}

Expand Down Expand Up @@ -959,6 +964,49 @@ impl<W: LayoutElement> ScrollingSpace<W> {
self.add_tile(Some(col_idx), tile, activate, width, is_full_width, None);
}

fn is_auto_tile_enabled(&self) -> bool {
self.options.layout.auto_tile.is_some()
}

fn auto_tile_max(&self) -> usize {
match &self.options.layout.auto_tile {
Some(at) => at.max_columns as usize,
None => 0,
}
}

/// Returns whether auto-tiling should apply to a new column at `idx`.
fn should_auto_tile(&self, idx: usize) -> bool {
if !self.is_auto_tile_enabled() {
return false;
}

let max = self.auto_tile_max();
if self.auto_tile_count >= max {
return false;
}

idx <= self.auto_tile_count
}

/// Redistribute widths of all auto-tiled columns to fill the screen equally.
fn redistribute_auto_tile_widths(&mut self) {
if self.auto_tile_count == 0 {
return;
}

let prop = 1.0 / self.auto_tile_count as f64;
for i in 0..self.auto_tile_count {
if i >= self.columns.len() {
break;
}
let col = &mut self.columns[i];
col.set_width_proportion(prop);
col.update_tile_sizes(true);
self.data[i].update(col);
}
}

pub fn add_column(
&mut self,
idx: Option<usize>,
Expand All @@ -976,6 +1024,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
}
});

// Determine if this new column should be auto-tiled.
let do_auto_tile = self.should_auto_tile(idx);

column.update_config(
self.view_size,
self.working_area,
Expand All @@ -990,6 +1041,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
self.active_column_idx += 1;
}

if do_auto_tile {
self.auto_tile_count += 1;
self.redistribute_auto_tile_widths();
}

// Animate movement of other columns.
let offset = self.column_x(idx + 1) - self.column_x(idx);
let config = anim_config.unwrap_or(self.options.animations.window_movement.0);
Expand Down Expand Up @@ -1179,6 +1235,12 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let column = self.columns.remove(column_idx);
self.data.remove(column_idx);

// If the removed column was in the auto-tile zone, redistribute.
if column_idx < self.auto_tile_count {
self.auto_tile_count -= 1;
self.redistribute_auto_tile_widths();
}

// Stop interactive resize.
if let Some(resize) = &self.interactive_resize {
if column
Expand Down Expand Up @@ -4854,6 +4916,13 @@ impl<W: LayoutElement> Column<W> {
self.update_tile_sizes(true);
}

fn set_width_proportion(&mut self, proportion: f64) {
self.width = ColumnWidth::Proportion(proportion);
self.is_full_width = false;
self.is_pending_maximized = false;
self.preset_width_idx = None;
}

fn set_column_width(&mut self, change: SizeChange, tile_idx: Option<usize>, animate: bool) {
let current = if self.is_full_width || self.is_pending_maximized {
ColumnWidth::Proportion(1.)
Expand Down