diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/focus_ring.rs | 101 | ||||
| -rw-r--r-- | src/layout/tile.rs | 22 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 2 |
3 files changed, 97 insertions, 28 deletions
diff --git a/src/layout/focus_ring.rs b/src/layout/focus_ring.rs index 0addd204..24013510 100644 --- a/src/layout/focus_ring.rs +++ b/src/layout/focus_ring.rs @@ -1,26 +1,41 @@ use std::iter::zip; use arrayvec::ArrayVec; -use niri_config; +use niri_config::{self, GradientRelativeTo}; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; use smithay::backend::renderer::element::Kind; -use smithay::utils::{Logical, Point, Scale, Size}; +use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; + +use crate::niri_render_elements; +use crate::render_helpers::gradient::GradientRenderElement; +use crate::render_helpers::renderer::NiriRenderer; #[derive(Debug)] pub struct FocusRing { buffers: [SolidColorBuffer; 4], locations: [Point<i32, Logical>; 4], + sizes: [Size<i32, Logical>; 4], + full_size: Size<i32, Logical>, + is_active: bool, is_border: bool, config: niri_config::FocusRing, } -pub type FocusRingRenderElement = SolidColorRenderElement; +niri_render_elements! { + FocusRingRenderElement => { + SolidColor = SolidColorRenderElement, + Gradient = GradientRenderElement, + } +} impl FocusRing { pub fn new(config: niri_config::FocusRing) -> Self { Self { buffers: Default::default(), locations: Default::default(), + sizes: Default::default(), + full_size: Default::default(), + is_active: false, is_border: false, config, } @@ -32,20 +47,25 @@ impl FocusRing { pub fn update(&mut self, win_size: Size<i32, Logical>, is_border: bool) { let width = i32::from(self.config.width); + self.full_size = win_size + Size::from((width * 2, width * 2)); if is_border { - self.buffers[0].resize((win_size.w + width * 2, width)); - self.buffers[1].resize((win_size.w + width * 2, width)); - self.buffers[2].resize((width, win_size.h)); - self.buffers[3].resize((width, win_size.h)); + self.sizes[0] = Size::from((win_size.w + width * 2, width)); + self.sizes[1] = Size::from((win_size.w + width * 2, width)); + self.sizes[2] = Size::from((width, win_size.h)); + self.sizes[3] = Size::from((width, win_size.h)); + + for (buf, size) in zip(&mut self.buffers, self.sizes) { + buf.resize(size); + } self.locations[0] = Point::from((-width, -width)); self.locations[1] = Point::from((-width, win_size.h)); self.locations[2] = Point::from((-width, 0)); self.locations[3] = Point::from((win_size.w, 0)); } else { - let size = win_size + Size::from((width * 2, width * 2)); - self.buffers[0].resize(size); + self.sizes[0] = self.full_size; + self.buffers[0].resize(self.sizes[0]); self.locations[0] = Point::from((-width, -width)); } @@ -62,12 +82,16 @@ impl FocusRing { for buf in &mut self.buffers { buf.set_color(color); } + + self.is_active = is_active; } - pub fn render( + pub fn render<R: NiriRenderer>( &self, + renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + view_size: Size<i32, Logical>, ) -> impl Iterator<Item = FocusRingRenderElement> { let mut rv = ArrayVec::<_, 4>::new(); @@ -75,23 +99,56 @@ impl FocusRing { return rv.into_iter(); } - let mut push = |buffer, location: Point<i32, Logical>| { - let elem = SolidColorRenderElement::from_buffer( - buffer, - location.to_physical_precise_round(scale), - scale, - 1., - Kind::Unspecified, - ); - rv.push(elem.into()); + let gradient = if self.is_active { + self.config.active_gradient + } else { + self.config.inactive_gradient + }; + + let full_rect = Rectangle::from_loc_and_size(location + self.locations[0], self.full_size); + let view_rect = Rectangle::from_loc_and_size((0, 0), view_size); + + let mut push = |buffer, location: Point<i32, Logical>, size: Size<i32, Logical>| { + let elem = gradient.and_then(|gradient| { + let gradient_area = match gradient.relative_to { + GradientRelativeTo::Window => full_rect, + GradientRelativeTo::WorkspaceView => view_rect, + }; + GradientRenderElement::new( + renderer, + scale, + Rectangle::from_loc_and_size(location, size), + gradient_area, + gradient.from.into(), + gradient.to.into(), + ((gradient.angle as f32) - 90.).to_radians(), + ) + .map(Into::into) + }); + + let elem = elem.unwrap_or_else(|| { + SolidColorRenderElement::from_buffer( + buffer, + location.to_physical_precise_round(scale), + scale, + 1., + Kind::Unspecified, + ) + .into() + }); + rv.push(elem); }; if self.is_border { - for (buf, loc) in zip(&self.buffers, self.locations) { - push(buf, location + loc); + for (buf, (loc, size)) in zip(&self.buffers, zip(self.locations, self.sizes)) { + push(buf, location + loc, size); } } else { - push(&self.buffers[0], location + self.locations[0]); + push( + &self.buffers[0], + location + self.locations[0], + self.sizes[0], + ); } rv.into_iter() diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 28bcfb47..ca2779fe 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -7,7 +7,7 @@ use smithay::backend::renderer::element::utils::RescaleRenderElement; use smithay::backend::renderer::element::{Element, Kind}; use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; -use super::focus_ring::FocusRing; +use super::focus_ring::{FocusRing, FocusRingRenderElement}; use super::{LayoutElement, LayoutElementRenderElement, Options}; use crate::animation::Animation; use crate::niri_render_elements; @@ -51,6 +51,7 @@ pub struct Tile<W: LayoutElement> { niri_render_elements! { TileRenderElement<R> => { LayoutElement = LayoutElementRenderElement<R>, + FocusRing = FocusRingRenderElement, SolidColor = SolidColorRenderElement, Offscreen = RescaleRenderElement<OffscreenRenderElement>, } @@ -297,6 +298,7 @@ impl<W: LayoutElement> Tile<W> { renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + view_size: Size<i32, Logical>, focus_ring: bool, ) -> impl Iterator<Item = TileRenderElement<R>> { let rv = self @@ -307,12 +309,21 @@ impl<W: LayoutElement> Tile<W> { let elem = self.effective_border_width().map(|width| { self.border - .render(location + Point::from((width, width)), scale) + .render( + renderer, + location + Point::from((width, width)), + scale, + view_size, + ) .map(Into::into) }); let rv = rv.chain(elem.into_iter().flatten()); - let elem = focus_ring.then(|| self.focus_ring.render(location, scale).map(Into::into)); + let elem = focus_ring.then(|| { + self.focus_ring + .render(renderer, location, scale, view_size) + .map(Into::into) + }); let rv = rv.chain(elem.into_iter().flatten()); let elem = self.is_fullscreen.then(|| { @@ -333,11 +344,12 @@ impl<W: LayoutElement> Tile<W> { renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + view_size: Size<i32, Logical>, focus_ring: bool, ) -> impl Iterator<Item = TileRenderElement<R>> { if let Some(anim) = &self.open_animation { let renderer = renderer.as_gles_renderer(); - let elements = self.render_inner(renderer, location, scale, focus_ring); + let elements = self.render_inner(renderer, location, scale, view_size, focus_ring); let elements = elements.collect::<Vec<TileRenderElement<_>>>(); let elem = OffscreenRenderElement::new( @@ -365,7 +377,7 @@ impl<W: LayoutElement> Tile<W> { } else { self.window().set_offscreen_element_id(None); - let elements = self.render_inner(renderer, location, scale, focus_ring); + let elements = self.render_inner(renderer, location, scale, view_size, focus_ring); None.into_iter().chain(Some(elements).into_iter().flatten()) } } diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 5e872340..b9016098 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -1188,7 +1188,7 @@ impl<W: LayoutElement> Workspace<W> { first = false; rv.extend( - tile.render(renderer, tile_pos, output_scale, focus_ring) + tile.render(renderer, tile_pos, output_scale, self.view_size, focus_ring) .map(Into::into), ); } |
