diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-07 09:36:08 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 07:29:33 -0800 |
| commit | c31b58e2c9a786fc8c96bba462190374535e6819 (patch) | |
| tree | 6b2b1e93b01cf3152c9e62fd483d4a09d02bfb05 /src/layout/scrolling.rs | |
| parent | b1630457571330335ece184ca5e7a1c1acffb107 (diff) | |
| download | niri-c31b58e2c9a786fc8c96bba462190374535e6819.tar.gz niri-c31b58e2c9a786fc8c96bba462190374535e6819.tar.bz2 niri-c31b58e2c9a786fc8c96bba462190374535e6819.zip | |
tab indicator: Implement place-within-column setting
Diffstat (limited to 'src/layout/scrolling.rs')
| -rw-r--r-- | src/layout/scrolling.rs | 149 |
1 files changed, 119 insertions, 30 deletions
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index 42de18c8..55ddfc1b 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -421,7 +421,23 @@ impl<W: LayoutElement> ScrollingSpace<W> { pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> { let border_config = rules.border.resolve_against(self.options.border); - compute_toplevel_bounds(border_config, self.working_area.size, self.options.gaps) + + let display_mode = rules + .default_column_display + .unwrap_or(self.options.default_column_display); + let will_tab = display_mode == ColumnDisplay::Tabbed; + let extra_size = if will_tab { + TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale) + } else { + Size::from((0., 0.)) + }; + + compute_toplevel_bounds( + border_config, + self.working_area.size, + extra_size, + self.options.gaps, + ) } pub fn new_window_size( @@ -432,10 +448,20 @@ impl<W: LayoutElement> ScrollingSpace<W> { ) -> Size<i32, Logical> { let border = rules.border.resolve_against(self.options.border); + let display_mode = rules + .default_column_display + .unwrap_or(self.options.default_column_display); + let will_tab = display_mode == ColumnDisplay::Tabbed; + let extra = if will_tab { + TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale) + } else { + Size::from((0., 0.)) + }; + let working_size = self.working_area.size; let width = if let Some(size) = width { - let size = match resolve_preset_size(size, &self.options, working_size.w) { + let size = match resolve_preset_size(size, &self.options, working_size.w, extra.w) { ResolvedSize::Tile(mut size) => { if !border.off { size -= border.width.0 * 2.; @@ -456,7 +482,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { } let height = if let Some(height) = height { - let height = match resolve_preset_size(height, &self.options, working_size.h) { + let height = match resolve_preset_size(height, &self.options, working_size.h, extra.h) { ResolvedSize::Tile(mut size) => { if !border.off { size -= border.width.0 * 2.; @@ -1994,6 +2020,10 @@ impl<W: LayoutElement> ScrollingSpace<W> { cancel_resize_for_column(&mut self.interactive_resize, col); col.set_column_display(display); + // With place_within_column, the tab indicator changes the column size immediately. + self.data[self.active_column_idx].update(col); + col.update_tile_sizes(true); + // Disable fullscreen if needed. if col.display_mode != ColumnDisplay::Tabbed && col.tiles.len() > 1 { let window = col.tiles[col.active_tile_idx].window().id().clone(); @@ -2224,8 +2254,16 @@ impl<W: LayoutElement> ScrollingSpace<W> { } }; - let size = Size::from((self.data[column_index].width, height)); - let loc = Point::from((self.column_x(column_index), y)); + // Adjust for place-within-column tab indicator. + let origin_x = col.tiles_origin().x; + let extra_w = if is_tabbed && !col.is_fullscreen { + col.tab_indicator.extra_size(col.tiles.len(), col.scale).w + } else { + 0. + }; + + let size = Size::from((self.data[column_index].width - extra_w, height)); + let loc = Point::from((self.column_x(column_index) + origin_x, y)); Rectangle::new(loc, size) } InsertPosition::Floating => return None, @@ -2472,6 +2510,9 @@ impl<W: LayoutElement> ScrollingSpace<W> { col.set_fullscreen(is_fullscreen); + // With place_within_column, the tab indicator changes the column size immediately. + self.data[col_idx].update(col); + // If we quickly fullscreen and unfullscreen before any window has a chance to receive the // request, we need to reset the offset. if col_idx == self.active_column_idx @@ -3016,6 +3057,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { } let is_tabbed = col.display_mode == ColumnDisplay::Tabbed; + let extra_size = col.extra_size(); // If transactions are disabled, also disable combined throttling, for more intuitive // behavior. In tabbed display mode, only one window is visible, so individual @@ -3063,6 +3105,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { let bounds = compute_toplevel_bounds( border_config, self.working_area.size, + extra_size, self.options.gaps, ); win.set_bounds(bounds); @@ -3352,6 +3395,10 @@ impl<W: LayoutElement> Column<W> { update_sizes = true; } + if self.options.tab_indicator != options.tab_indicator { + update_sizes = true; + } + for (tile, data) in zip(&mut self.tiles, &mut self.data) { tile.update_config(view_size, scale, options.clone()); data.update(tile); @@ -3545,20 +3592,34 @@ impl<W: LayoutElement> Column<W> { } } + /// Extra size taken up by elements in the column such as the tab indicator. + fn extra_size(&self) -> Size<f64, Logical> { + if self.display_mode == ColumnDisplay::Tabbed { + self.tab_indicator.extra_size(self.tiles.len(), self.scale) + } else { + Size::from((0., 0.)) + } + } + fn resolve_preset_width(&self, preset: PresetSize) -> ResolvedSize { - resolve_preset_size(preset, &self.options, self.working_area.size.w) + let extra = self.extra_size(); + resolve_preset_size(preset, &self.options, self.working_area.size.w, extra.w) } fn resolve_preset_height(&self, preset: PresetSize) -> ResolvedSize { - resolve_preset_size(preset, &self.options, self.working_area.size.h) + let extra = self.extra_size(); + resolve_preset_size(preset, &self.options, self.working_area.size.h, extra.h) } fn resolve_column_width(&self, width: ColumnWidth) -> f64 { let working_size = self.working_area.size; let gaps = self.options.gaps; + let extra = self.extra_size(); match width { - ColumnWidth::Proportion(proportion) => (working_size.w - gaps) * proportion - gaps, + ColumnWidth::Proportion(proportion) => { + (working_size.w - gaps) * proportion - gaps - extra.w + } ColumnWidth::Fixed(width) => width, } } @@ -3618,10 +3679,11 @@ impl<W: LayoutElement> Column<W> { }; let working_size = self.working_area.size; + let extra_size = self.extra_size(); let width = self.resolve_column_width(width); let width = f64::max(f64::min(width, max_width), min_width); - let max_tile_height = working_size.h - self.options.gaps * 2.; + let max_tile_height = working_size.h - self.options.gaps * 2. - extra_size.h; // If there are multiple windows in a column, clamp the non-auto window's height according // to other windows' min sizes. @@ -3846,12 +3908,20 @@ impl<W: LayoutElement> Column<W> { } fn width(&self) -> f64 { - self.data + let mut tiles_width = self + .data .iter() .map(|data| NotNan::new(data.size.w).unwrap()) .max() .map(NotNan::into_inner) - .unwrap() + .unwrap(); + + if self.display_mode == ColumnDisplay::Tabbed && !self.is_fullscreen { + let extra_size = self.tab_indicator.extra_size(self.tiles.len(), self.scale); + tiles_width += extra_size.w; + } + + tiles_width } fn focus_index(&mut self, index: u8) { @@ -4002,7 +4072,7 @@ impl<W: LayoutElement> Column<W> { let current = if full == 0. { 1. } else { - (current_px + self.options.gaps) / full + (current_px + self.options.gaps + self.extra_size().w) / full }; let proportion = (current + delta / 100.).clamp(0., MAX_F); ColumnWidth::Proportion(proportion) @@ -4037,6 +4107,7 @@ impl<W: LayoutElement> Column<W> { let working_size = self.working_area.size.h; let gaps = self.options.gaps; + let extra_size = self.extra_size().h; let full = working_size - gaps; let current_prop = if full == 0. { 1. @@ -4050,13 +4121,13 @@ impl<W: LayoutElement> Column<W> { let mut window_height = match change { SizeChange::SetFixed(fixed) => f64::from(fixed), SizeChange::SetProportion(proportion) => { - let tile_height = (working_size - gaps) * (proportion / 100.) - gaps; + let tile_height = (working_size - gaps) * (proportion / 100.) - gaps - extra_size; tile.window_height_for_tile_height(tile_height) } SizeChange::AdjustFixed(delta) => current_window_px + f64::from(delta), SizeChange::AdjustProportion(delta) => { let proportion = current_prop + delta / 100.; - let tile_height = (working_size - gaps) * proportion - gaps; + let tile_height = (working_size - gaps) * proportion - gaps - extra_size; tile.window_height_for_tile_height(tile_height) } }; @@ -4072,7 +4143,7 @@ impl<W: LayoutElement> Column<W> { .map(|(_, tile)| f64::max(1., tile.min_size().h) + gaps) .sum::<f64>() }; - let height_left = working_size - gaps - min_height_taken - gaps; + let height_left = working_size - extra_size - gaps - min_height_taken - gaps; let height_left = f64::max(1., tile.window_height_for_tile_height(height_left)); window_height = f64::min(height_left, window_height); @@ -4219,6 +4290,12 @@ impl<W: LayoutElement> Column<W> { origin.y += self.working_area.loc.y + self.options.gaps; + if self.display_mode == ColumnDisplay::Tabbed { + origin += self + .tab_indicator + .content_offset(self.tiles.len(), self.scale); + } + origin } @@ -4234,11 +4311,16 @@ impl<W: LayoutElement> Column<W> { let center = self.options.center_focused_column == CenterFocusedColumn::Always; let gaps = self.options.gaps; let tabbed = self.display_mode == ColumnDisplay::Tabbed; - let col_width = if self.tiles.is_empty() { - 0. - } else { - self.width() - }; + + // Does not include extra size from the tab indicator. + let tiles_width = self + .data + .iter() + .map(|data| NotNan::new(data.size.w).unwrap()) + .max() + .map(NotNan::into_inner) + .unwrap_or(0.); + let mut origin = self.tiles_origin(); // Chain with a dummy value to be able to get one past all tiles' Y. @@ -4253,9 +4335,9 @@ impl<W: LayoutElement> Column<W> { let mut pos = origin; if center { - pos.x += (col_width - data.size.w) / 2.; + pos.x += (tiles_width - data.size.w) / 2.; } else if data.interactively_resizing_by_left_edge { - pos.x += col_width - data.size.w; + pos.x += tiles_width - data.size.w; } if !tabbed { @@ -4354,6 +4436,7 @@ impl<W: LayoutElement> Column<W> { } let working_size = self.working_area.size; + let extra_size = self.extra_size(); let gaps = self.options.gaps; let mut found_fixed = false; @@ -4393,8 +4476,8 @@ impl<W: LayoutElement> Column<W> { && working_size.h.round() == working_size.h && gaps.round() == gaps { - let total_height = requested_tile_height + gaps * 2.; - let total_min_height = min_tile_height + gaps * 2.; + let total_height = requested_tile_height + gaps * 2. + extra_size.h; + let total_min_height = min_tile_height + gaps * 2. + extra_size.h; let max_height = f64::max(total_min_height, working_size.h); assert!( total_height <= max_height, @@ -4413,8 +4496,8 @@ impl<W: LayoutElement> Column<W> { && working_size.h.round() == working_size.h && gaps.round() == gaps { - total_height += gaps * (tile_count + 1) as f64; - total_min_height += gaps * (tile_count + 1) as f64; + total_height += gaps * (tile_count + 1) as f64 + extra_size.h; + total_min_height += gaps * (tile_count + 1) as f64 + extra_size.h; let max_height = f64::max(total_min_height, working_size.h); assert!( total_height <= max_height, @@ -4492,6 +4575,7 @@ fn compute_working_area( fn compute_toplevel_bounds( border_config: niri_config::Border, working_area_size: Size<f64, Logical>, + extra_size: Size<f64, Logical>, gaps: f64, ) -> Size<i32, Logical> { let mut border = 0.; @@ -4500,8 +4584,8 @@ fn compute_toplevel_bounds( } Size::from(( - f64::max(working_area_size.w - gaps * 2. - border, 1.), - f64::max(working_area_size.h - gaps * 2. - border, 1.), + f64::max(working_area_size.w - gaps * 2. - extra_size.w - border, 1.), + f64::max(working_area_size.h - gaps * 2. - extra_size.h - border, 1.), )) .to_i32_floor() } @@ -4521,10 +4605,15 @@ fn cancel_resize_for_column<W: LayoutElement>( } } -fn resolve_preset_size(preset: PresetSize, options: &Options, view_size: f64) -> ResolvedSize { +fn resolve_preset_size( + preset: PresetSize, + options: &Options, + view_size: f64, + extra_size: f64, +) -> ResolvedSize { match preset { PresetSize::Proportion(proportion) => { - ResolvedSize::Tile((view_size - options.gaps) * proportion - options.gaps) + ResolvedSize::Tile((view_size - options.gaps) * proportion - options.gaps - extra_size) } PresetSize::Fixed(width) => ResolvedSize::Window(f64::from(width)), } |
