diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-06-17 09:16:28 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-06-18 14:01:28 +0300 |
| commit | 1dae45c58d7eabeda21ef490d712915890bf6cff (patch) | |
| tree | 62c473ab1662a1161ed522517ea57b7bd8db340c /src/layout/focus_ring.rs | |
| parent | 997119c44338ad96a40b4a1d6e958f77062a37ef (diff) | |
| download | niri-1dae45c58d7eabeda21ef490d712915890bf6cff.tar.gz niri-1dae45c58d7eabeda21ef490d712915890bf6cff.tar.bz2 niri-1dae45c58d7eabeda21ef490d712915890bf6cff.zip | |
Refactor layout to fractional-logical
Lets borders, gaps, and everything else stay pixel-perfect even with
fractional scale. Allows setting fractional border widths, gaps,
struts.
See the new wiki .md for more details.
Diffstat (limited to 'src/layout/focus_ring.rs')
| -rw-r--r-- | src/layout/focus_ring.rs | 73 |
1 files changed, 37 insertions, 36 deletions
diff --git a/src/layout/focus_ring.rs b/src/layout/focus_ring.rs index b198e838..e7c0388b 100644 --- a/src/layout/focus_ring.rs +++ b/src/layout/focus_ring.rs @@ -1,23 +1,22 @@ -use std::cmp::{max, min}; use std::iter::zip; use arrayvec::ArrayVec; use niri_config::{CornerRadius, Gradient, GradientRelativeTo}; -use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; use smithay::backend::renderer::element::Kind; -use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; +use smithay::utils::{Logical, Point, Rectangle, Size}; use crate::niri_render_elements; use crate::render_helpers::border::BorderRenderElement; use crate::render_helpers::renderer::NiriRenderer; +use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement}; #[derive(Debug)] pub struct FocusRing { buffers: [SolidColorBuffer; 8], - locations: [Point<i32, Logical>; 8], - sizes: [Size<i32, Logical>; 8], + locations: [Point<f64, Logical>; 8], + sizes: [Size<f64, Logical>; 8], borders: [BorderRenderElement; 8], - full_size: Size<i32, Logical>, + full_size: Size<f64, Logical>, is_border: bool, use_border_shader: bool, config: niri_config::FocusRing, @@ -56,14 +55,15 @@ impl FocusRing { pub fn update_render_elements( &mut self, - win_size: Size<i32, Logical>, + win_size: Size<f64, Logical>, is_active: bool, is_border: bool, - view_rect: Rectangle<i32, Logical>, + view_rect: Rectangle<f64, Logical>, radius: CornerRadius, + scale: f64, ) { - let width = i32::from(self.config.width); - self.full_size = win_size + Size::from((width * 2, width * 2)); + let width = self.config.width.0; + self.full_size = win_size + Size::from((width, width)).upscale(2.); let color = if is_active { self.config.active_color @@ -107,39 +107,48 @@ impl FocusRing { 0. }; + let ceil = |logical: f64| (logical * scale).ceil() / scale; + + // All of this stuff should end up aligned to physical pixels because: + // * Window size and border width are rounded to physical pixels before being passed to this + // function. + // * We will ceil the corner radii below. + // * We do not divide anything, only add, subtract and multiply by integers. + // * At rendering time, tile positions are rounded to physical pixels. + if is_border { - let top_left = max(width, radius.top_left.ceil() as i32); - let top_right = min( + let top_left = f64::max(width, ceil(f64::from(radius.top_left))); + let top_right = f64::min( self.full_size.w - top_left, - max(width, radius.top_right.ceil() as i32), + f64::max(width, ceil(f64::from(radius.top_right))), ); - let bottom_left = min( + let bottom_left = f64::min( self.full_size.h - top_left, - max(width, radius.bottom_left.ceil() as i32), + f64::max(width, ceil(f64::from(radius.bottom_left))), ); - let bottom_right = min( + let bottom_right = f64::min( self.full_size.h - top_right, - min( + f64::min( self.full_size.w - bottom_left, - max(width, radius.bottom_right.ceil() as i32), + f64::max(width, ceil(f64::from(radius.bottom_right))), ), ); // Top edge. - self.sizes[0] = Size::from((win_size.w + width * 2 - top_left - top_right, width)); + self.sizes[0] = Size::from((win_size.w + width * 2. - top_left - top_right, width)); self.locations[0] = Point::from((-width + top_left, -width)); // Bottom edge. self.sizes[1] = - Size::from((win_size.w + width * 2 - bottom_left - bottom_right, width)); + Size::from((win_size.w + width * 2. - bottom_left - bottom_right, width)); self.locations[1] = Point::from((-width + bottom_left, win_size.h)); // Left edge. - self.sizes[2] = Size::from((width, win_size.h + width * 2 - top_left - bottom_left)); + self.sizes[2] = Size::from((width, win_size.h + width * 2. - top_left - bottom_left)); self.locations[2] = Point::from((-width, -width + top_left)); // Right edge. - self.sizes[3] = Size::from((width, win_size.h + width * 2 - top_right - bottom_right)); + self.sizes[3] = Size::from((width, win_size.h + width * 2. - top_right - bottom_right)); self.locations[3] = Point::from((win_size.w, -width + top_right)); // Top-left corner. @@ -203,8 +212,7 @@ impl FocusRing { pub fn render( &self, renderer: &mut impl NiriRenderer, - location: Point<i32, Logical>, - scale: Scale<f64>, + location: Point<f64, Logical>, ) -> impl Iterator<Item = FocusRingRenderElement> { let mut rv = ArrayVec::<_, 8>::new(); @@ -215,24 +223,17 @@ impl FocusRing { let border_width = -self.locations[0].y; // If drawing as a border with width = 0, then there's nothing to draw. - if self.is_border && border_width == 0 { + if self.is_border && border_width == 0. { return rv.into_iter(); } let has_border_shader = BorderRenderElement::has_shader(renderer); - let mut push = |buffer, border: &BorderRenderElement, location: Point<i32, Logical>| { + let mut push = |buffer, border: &BorderRenderElement, location: Point<f64, Logical>| { let elem = if self.use_border_shader && has_border_shader { border.clone().with_location(location).into() } else { - SolidColorRenderElement::from_buffer( - buffer, - location.to_physical_precise_round(scale), - scale, - 1., - Kind::Unspecified, - ) - .into() + SolidColorRenderElement::from_buffer(buffer, location, 1., Kind::Unspecified).into() }; rv.push(elem); }; @@ -252,8 +253,8 @@ impl FocusRing { rv.into_iter() } - pub fn width(&self) -> i32 { - self.config.width.into() + pub fn width(&self) -> f64 { + self.config.width.0 } pub fn is_off(&self) -> bool { |
