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.
This commit is contained in:
Ivan Molodetskikh
2024-06-17 09:16:28 +03:00
parent 997119c443
commit 1dae45c58d
35 changed files with 1050 additions and 652 deletions
@@ -59,15 +59,15 @@ impl TestCase for GradientAngle {
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
let (a, b) = (size.w / 4, size.h / 4);
let size = (size.w - a * 2, size.h - b * 2);
let area = Rectangle::from_loc_and_size((a, b), size);
let area = Rectangle::from_loc_and_size((a, b), size).to_f64();
[BorderRenderElement::new(
area.size,
Rectangle::from_loc_and_size((0, 0), area.size),
Rectangle::from_loc_and_size((0., 0.), area.size),
[1., 0., 0., 1.],
[0., 1., 0., 1.],
self.angle - FRAC_PI_2,
Rectangle::from_loc_and_size((0, 0), area.size),
Rectangle::from_loc_and_size((0., 0.), area.size),
0.,
CornerRadius::default(),
)
+9 -7
View File
@@ -5,10 +5,10 @@ use std::time::Duration;
use niri::animation::ANIMATION_SLOWDOWN;
use niri::layout::focus_ring::FocusRing;
use niri::render_helpers::border::BorderRenderElement;
use niri_config::{Color, CornerRadius};
use niri_config::{Color, CornerRadius, FloatOrInt};
use smithay::backend::renderer::element::RenderElement;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size};
use smithay::utils::{Logical, Physical, Point, Rectangle, Size};
use super::TestCase;
@@ -22,7 +22,7 @@ impl GradientArea {
pub fn new(_size: Size<i32, Logical>) -> Self {
let border = FocusRing::new(niri_config::FocusRing {
off: false,
width: 1,
width: FloatOrInt(1.),
active_color: Color::new(255, 255, 255, 128),
inactive_color: Color::default(),
active_gradient: None,
@@ -75,13 +75,14 @@ impl TestCase for GradientArea {
let (a, b) = (size.w / 4, size.h / 4);
let rect_size = (size.w - a * 2, size.h - b * 2);
let area = Rectangle::from_loc_and_size((a, b), rect_size);
let area = Rectangle::from_loc_and_size((a, b), rect_size).to_f64();
let g_size = Size::from((
(size.w as f32 / 8. + size.w as f32 / 8. * 7. * f).round() as i32,
(size.h as f32 / 8. + size.h as f32 / 8. * 7. * f).round() as i32,
));
let g_loc = ((size.w - g_size.w) / 2, (size.h - g_size.h) / 2);
let g_loc = Point::from(((size.w - g_size.w) / 2, (size.h - g_size.h) / 2)).to_f64();
let g_size = g_size.to_f64();
let mut g_area = Rectangle::from_loc_and_size(g_loc, g_size);
g_area.loc -= area.loc;
@@ -91,10 +92,11 @@ impl TestCase for GradientArea {
true,
Rectangle::default(),
CornerRadius::default(),
1.,
);
rv.extend(
self.border
.render(renderer, Point::from(g_loc), Scale::from(1.))
.render(renderer, g_loc)
.map(|elem| Box::new(elem) as _),
);
@@ -105,7 +107,7 @@ impl TestCase for GradientArea {
[1., 0., 0., 1.],
[0., 1., 0., 1.],
FRAC_PI_4,
Rectangle::from_loc_and_size((0, 0), rect_size),
Rectangle::from_loc_and_size((0, 0), rect_size).to_f64(),
0.,
CornerRadius::default(),
)
+2 -2
View File
@@ -5,7 +5,7 @@ use niri::layout::workspace::ColumnWidth;
use niri::layout::{LayoutElement as _, Options};
use niri::render_helpers::RenderTarget;
use niri::utils::get_monotonic_time;
use niri_config::Color;
use niri_config::{Color, FloatOrInt};
use smithay::backend::renderer::element::RenderElement;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::desktop::layer_map_for_output;
@@ -49,7 +49,7 @@ impl Layout {
},
border: niri_config::Border {
off: false,
width: 4,
width: FloatOrInt(4.),
active_color: Color::new(255, 163, 72, 255),
inactive_color: Color::new(50, 50, 50, 255),
active_gradient: None,
+11 -10
View File
@@ -3,7 +3,7 @@ use std::time::Duration;
use niri::layout::Options;
use niri::render_helpers::RenderTarget;
use niri_config::Color;
use niri_config::{Color, FloatOrInt};
use smithay::backend::renderer::element::RenderElement;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size};
@@ -20,7 +20,7 @@ impl Tile {
pub fn freeform(size: Size<i32, Logical>) -> Self {
let window = TestWindow::freeform(0);
let mut rv = Self::with_window(window);
rv.tile.request_tile_size(size, false);
rv.tile.request_tile_size(size.to_f64(), false);
rv.window.communicate();
rv
}
@@ -28,7 +28,7 @@ impl Tile {
pub fn fixed_size(size: Size<i32, Logical>) -> Self {
let window = TestWindow::fixed_size(0);
let mut rv = Self::with_window(window);
rv.tile.request_tile_size(size, false);
rv.tile.request_tile_size(size.to_f64(), false);
rv.window.communicate();
rv
}
@@ -37,7 +37,7 @@ impl Tile {
let window = TestWindow::fixed_size(0);
window.set_csd_shadow_width(64);
let mut rv = Self::with_window(window);
rv.tile.request_tile_size(size, false);
rv.tile.request_tile_size(size.to_f64(), false);
rv.window.communicate();
rv
}
@@ -71,13 +71,13 @@ impl Tile {
},
border: niri_config::Border {
off: false,
width: 32,
width: FloatOrInt(32.),
active_color: Color::new(255, 163, 72, 255),
..Default::default()
},
..Default::default()
};
let tile = niri::layout::tile::Tile::new(window.clone(), Rc::new(options));
let tile = niri::layout::tile::Tile::new(window.clone(), 1., Rc::new(options));
Self { window, tile }
}
}
@@ -85,7 +85,7 @@ impl Tile {
impl TestCase for Tile {
fn resize(&mut self, width: i32, height: i32) {
self.tile
.request_tile_size(Size::from((width, height)), false);
.request_tile_size(Size::from((width, height)).to_f64(), false);
self.window.communicate();
}
@@ -102,12 +102,13 @@ impl TestCase for Tile {
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
let tile_size = self.tile.tile_size().to_physical(1);
let location = Point::from(((size.w - tile_size.w) / 2, (size.h - tile_size.h) / 2));
let size = size.to_f64();
let tile_size = self.tile.tile_size().to_physical(1.);
let location = Point::from((size.w - tile_size.w, size.h - tile_size.h)).downscale(2.);
self.tile.update(
true,
Rectangle::from_loc_and_size((-location.x, -location.y), size.to_logical(1)),
Rectangle::from_loc_and_size((-location.x, -location.y), size.to_logical(1.)),
);
self.tile
.render(
+3 -1
View File
@@ -47,7 +47,9 @@ impl TestCase for Window {
size: Size<i32, Physical>,
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
let win_size = self.window.size().to_physical(1);
let location = Point::from(((size.w - win_size.w) / 2, (size.h - win_size.h) / 2));
let location = Point::from((size.w - win_size.w, size.h - win_size.h))
.to_f64()
.downscale(2.);
self.window
.render(
+10 -12
View File
@@ -6,9 +6,9 @@ use niri::layout::{
InteractiveResizeData, LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot,
};
use niri::render_helpers::renderer::NiriRenderer;
use niri::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
use niri::render_helpers::{RenderTarget, SplitElements};
use niri::window::ResolvedWindowRules;
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
use smithay::backend::renderer::element::{Id, Kind};
use smithay::output::{self, Output};
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
@@ -37,7 +37,7 @@ impl TestWindow {
let size = Size::from((100, 200));
let min_size = Size::from((0, 0));
let max_size = Size::from((0, 0));
let buffer = SolidColorBuffer::new(size, [0.15, 0.64, 0.41, 1.]);
let buffer = SolidColorBuffer::new(size.to_f64(), [0.15, 0.64, 0.41, 1.]);
Self {
id,
@@ -49,7 +49,7 @@ impl TestWindow {
buffer,
pending_fullscreen: false,
csd_shadow_width: 0,
csd_shadow_buffer: SolidColorBuffer::new((0, 0), [0., 0., 0., 0.3]),
csd_shadow_buffer: SolidColorBuffer::new((0., 0.), [0., 0., 0., 0.3]),
})),
}
}
@@ -112,14 +112,14 @@ impl TestWindow {
if inner.size != new_size {
inner.size = new_size;
inner.buffer.resize(new_size);
inner.buffer.resize(new_size.to_f64());
rv = true;
}
let mut csd_shadow_size = new_size;
csd_shadow_size.w += inner.csd_shadow_width * 2;
csd_shadow_size.h += inner.csd_shadow_width * 2;
inner.csd_shadow_buffer.resize(csd_shadow_size);
inner.csd_shadow_buffer.resize(csd_shadow_size.to_f64());
rv
}
@@ -147,8 +147,8 @@ impl LayoutElement for TestWindow {
fn render<R: NiriRenderer>(
&self,
_renderer: &mut R,
location: Point<i32, Logical>,
scale: Scale<f64>,
location: Point<f64, Logical>,
_scale: Scale<f64>,
alpha: f32,
_target: RenderTarget,
) -> SplitElements<LayoutElementRenderElement<R>> {
@@ -158,17 +158,15 @@ impl LayoutElement for TestWindow {
normal: vec![
SolidColorRenderElement::from_buffer(
&inner.buffer,
location.to_physical_precise_round(scale),
scale,
location,
alpha,
Kind::Unspecified,
)
.into(),
SolidColorRenderElement::from_buffer(
&inner.csd_shadow_buffer,
(location - Point::from((inner.csd_shadow_width, inner.csd_shadow_width)))
.to_physical_precise_round(scale),
scale,
location
- Point::from((inner.csd_shadow_width, inner.csd_shadow_width)).to_f64(),
alpha,
Kind::Unspecified,
)