aboutsummaryrefslogtreecommitdiff
path: root/src/layout/focus_ring.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-06-17 09:16:28 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-06-18 14:01:28 +0300
commit1dae45c58d7eabeda21ef490d712915890bf6cff (patch)
tree62c473ab1662a1161ed522517ea57b7bd8db340c /src/layout/focus_ring.rs
parent997119c44338ad96a40b4a1d6e958f77062a37ef (diff)
downloadniri-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.rs73
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 {