mirror of
https://github.com/YaLTeR/niri.git
synced 2024-08-17 16:20:23 +03:00
Merge a89c800c7f
into a5a34934df
This commit is contained in:
commit
ff20757e7d
@ -422,6 +422,8 @@ pub struct Gradient {
|
||||
pub angle: i16,
|
||||
#[knuffel(property, default)]
|
||||
pub relative_to: GradientRelativeTo,
|
||||
#[knuffel(property(name="in"), str, default)]
|
||||
pub in_: GradientInterpolation,
|
||||
}
|
||||
|
||||
#[derive(knuffel::DecodeScalar, Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
@ -431,6 +433,30 @@ pub enum GradientRelativeTo {
|
||||
WorkspaceView,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq)]
|
||||
pub struct GradientInterpolation {
|
||||
pub color_space: GradientColorSpace,
|
||||
pub hue_interpol: HueInterpolation
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum GradientColorSpace {
|
||||
#[default]
|
||||
Srgb,
|
||||
SrgbLinear,
|
||||
Oklab,
|
||||
Oklch,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum HueInterpolation {
|
||||
#[default]
|
||||
Shorter,
|
||||
Longer,
|
||||
Increasing,
|
||||
Decreasing,
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Border {
|
||||
#[knuffel(child)]
|
||||
@ -503,7 +529,8 @@ impl Color {
|
||||
impl From<Color> for [f32; 4] {
|
||||
fn from(c: Color) -> Self {
|
||||
let [r, g, b, a] = [c.r, c.g, c.b, c.a].map(|x| x as f32 / 255.);
|
||||
[r * a, g * a, b * a, a]
|
||||
//[r * a, g * a, b * a, a]
|
||||
[r, g, b, a]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1423,6 +1450,55 @@ impl CornerRadius {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GradientInterpolation {
|
||||
type Err = miette::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut iter = s.split_whitespace();
|
||||
let in_part1 = iter.next();
|
||||
let in_part2 = iter.next();
|
||||
let in_part3 = iter.next();
|
||||
|
||||
let color = if in_part1 != None {
|
||||
let in_str = in_part1.unwrap();
|
||||
match in_str {
|
||||
"srgb" => GradientColorSpace::Srgb,
|
||||
"srgb-linear" => GradientColorSpace::SrgbLinear,
|
||||
"oklab" => GradientColorSpace::Oklab,
|
||||
"oklch" => GradientColorSpace::Oklch,
|
||||
&_ => return Err(miette!("Invalid color-space: {in_str}"))
|
||||
}
|
||||
} else {
|
||||
GradientColorSpace::Srgb
|
||||
};
|
||||
|
||||
let interpolation = if in_part2 != None {
|
||||
let in_str = in_part2.unwrap();
|
||||
if color != GradientColorSpace::Oklch {
|
||||
return Err(miette!("There's a value: {in_str} after a non polar colorspace"))
|
||||
}
|
||||
if in_part3 == None || in_part3.unwrap() != "hue" {
|
||||
return Err(miette!("Invalid hue-interpolation: {in_str} you may be missing 'hue' at the end."))
|
||||
} else if iter.next() == None {
|
||||
match in_str {
|
||||
"shorter" => HueInterpolation::Shorter,
|
||||
"longer" => HueInterpolation::Longer,
|
||||
"increasing" => HueInterpolation::Increasing,
|
||||
"decreasing" => HueInterpolation::Decreasing,
|
||||
&_ => return Err(miette!("Invalid hue-interpolation: {in_str}"))
|
||||
}
|
||||
} else {
|
||||
// this is a placeholder and should be changed if anything is added to in
|
||||
return Err(miette!("Theres a missing indicator ’hue’ from ’in’ "))
|
||||
}
|
||||
} else {
|
||||
HueInterpolation::Shorter
|
||||
};
|
||||
|
||||
Ok( Self { color_space: color, hue_interpol: interpolation } )
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Color {
|
||||
type Err = miette::Error;
|
||||
|
||||
@ -2778,6 +2854,10 @@ mod tests {
|
||||
to: Color::new(0, 128, 255, 255),
|
||||
angle: 180,
|
||||
relative_to: GradientRelativeTo::WorkspaceView,
|
||||
in_ : GradientInterpolation {
|
||||
color_space: GradientColorSpace::Srgb,
|
||||
hue_interpol: HueInterpolation::Shorter,
|
||||
}
|
||||
}),
|
||||
inactive_gradient: None,
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ use std::time::Duration;
|
||||
|
||||
use niri::animation::ANIMATION_SLOWDOWN;
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::CornerRadius;
|
||||
use niri_config::{CornerRadius, GradientInterpolation};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
@ -64,6 +64,7 @@ impl TestCase for GradientAngle {
|
||||
[BorderRenderElement::new(
|
||||
area.size,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
GradientInterpolation::default(),
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
self.angle - FRAC_PI_2,
|
||||
|
@ -5,7 +5,7 @@ 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, FloatOrInt};
|
||||
use niri_config::{Color, CornerRadius, FloatOrInt, GradientInterpolation};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Point, Rectangle, Size};
|
||||
@ -104,6 +104,7 @@ impl TestCase for GradientArea {
|
||||
[BorderRenderElement::new(
|
||||
area.size,
|
||||
g_area,
|
||||
GradientInterpolation::default(),
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
FRAC_PI_4,
|
||||
|
51
niri-visual-tests/src/cases/gradient_oklab.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklab.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklab {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklab {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklab,
|
||||
hue_interpol: HueInterpolation::Shorter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklab {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_oklch_alpha.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklch_alpha.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklchAlpha {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklchAlpha {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklch,
|
||||
hue_interpol: HueInterpolation::Longer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklchAlpha {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 0.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_oklch_decreasing.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklch_decreasing.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklchDecreasing {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklchDecreasing {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklch,
|
||||
hue_interpol: HueInterpolation::Decreasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklchDecreasing {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_oklch_increasing.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklch_increasing.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklchIncreasing {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklchIncreasing {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklch,
|
||||
hue_interpol: HueInterpolation::Increasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklchIncreasing {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_oklch_longer.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklch_longer.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklchLonger {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklchLonger {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklch,
|
||||
hue_interpol: HueInterpolation::Longer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklchLonger {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_oklch_shorter.rs
Normal file
51
niri-visual-tests/src/cases/gradient_oklch_shorter.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientOklchShorter {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientOklchShorter {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Oklch,
|
||||
hue_interpol: HueInterpolation::Shorter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientOklchShorter {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_srgb.rs
Normal file
51
niri-visual-tests/src/cases/gradient_srgb.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientSrgb {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientSrgb {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::Srgb,
|
||||
hue_interpol: HueInterpolation::Shorter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientSrgb {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
51
niri-visual-tests/src/cases/gradient_srgblinear.rs
Normal file
51
niri-visual-tests/src/cases/gradient_srgblinear.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, HueInterpolation, GradientColorSpace};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Logical, Physical, Rectangle, Size};
|
||||
|
||||
use super::TestCase;
|
||||
|
||||
pub struct GradientSrgbLinear {
|
||||
gradient_format: GradientInterpolation,
|
||||
}
|
||||
|
||||
impl GradientSrgbLinear {
|
||||
pub fn new(_size: Size<i32, Logical>) -> Self {
|
||||
Self {
|
||||
gradient_format: GradientInterpolation{
|
||||
color_space: GradientColorSpace::SrgbLinear,
|
||||
hue_interpol: HueInterpolation::Shorter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestCase for GradientSrgbLinear {
|
||||
fn render(
|
||||
&mut self,
|
||||
_renderer: &mut GlesRenderer,
|
||||
size: Size<i32, Physical>,
|
||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||
let (a, b) = (size.w / 6, size.h / 3);
|
||||
let size = (size.w - a * 2, size.h - b * 2);
|
||||
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),
|
||||
self.gradient_format,
|
||||
[1., 0., 0., 1.],
|
||||
[0., 1., 0., 1.],
|
||||
0.,
|
||||
Rectangle::from_loc_and_size((0., 0.), area.size),
|
||||
0.,
|
||||
CornerRadius::default(),
|
||||
1.,
|
||||
)
|
||||
.with_location(area.loc)]
|
||||
.into_iter()
|
||||
.map(|elem| Box::new(elem) as _)
|
||||
.collect()
|
||||
}
|
||||
}
|
@ -6,6 +6,14 @@ use smithay::utils::{Physical, Size};
|
||||
|
||||
pub mod gradient_angle;
|
||||
pub mod gradient_area;
|
||||
pub mod gradient_srgb;
|
||||
pub mod gradient_srgblinear;
|
||||
pub mod gradient_oklab;
|
||||
pub mod gradient_oklch_shorter;
|
||||
pub mod gradient_oklch_longer;
|
||||
pub mod gradient_oklch_increasing;
|
||||
pub mod gradient_oklch_decreasing;
|
||||
pub mod gradient_oklch_alpha;
|
||||
pub mod layout;
|
||||
pub mod tile;
|
||||
pub mod window;
|
||||
|
@ -5,6 +5,7 @@ use std::env;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use adw::prelude::{AdwApplicationWindowExt, NavigationPageExt};
|
||||
use cases::gradient_oklch_alpha::GradientOklchAlpha;
|
||||
use cases::tile::Tile;
|
||||
use cases::window::Window;
|
||||
use gtk::prelude::{
|
||||
@ -18,6 +19,13 @@ use tracing_subscriber::EnvFilter;
|
||||
|
||||
use crate::cases::gradient_angle::GradientAngle;
|
||||
use crate::cases::gradient_area::GradientArea;
|
||||
use crate::cases::gradient_srgb::GradientSrgb;
|
||||
use crate::cases::gradient_srgblinear::GradientSrgbLinear;
|
||||
use crate::cases::gradient_oklab::GradientOklab;
|
||||
use crate::cases::gradient_oklch_shorter::GradientOklchShorter;
|
||||
use crate::cases::gradient_oklch_longer::GradientOklchLonger;
|
||||
use crate::cases::gradient_oklch_increasing::GradientOklchIncreasing;
|
||||
use crate::cases::gradient_oklch_decreasing::GradientOklchDecreasing;
|
||||
use crate::cases::layout::Layout;
|
||||
use crate::cases::TestCase;
|
||||
|
||||
@ -112,6 +120,14 @@ fn build_ui(app: &adw::Application) {
|
||||
|
||||
s.add(GradientAngle::new, "Gradient - Angle");
|
||||
s.add(GradientArea::new, "Gradient - Area");
|
||||
s.add(GradientSrgb::new, "Gradient - Srgb");
|
||||
s.add(GradientSrgbLinear::new, "Gradient - SrgbLinear");
|
||||
s.add(GradientOklab::new, "Gradient - Oklab");
|
||||
s.add(GradientOklchShorter::new, "Gradient - Oklch Shorter");
|
||||
s.add(GradientOklchLonger::new, "Gradient - Oklch Longer");
|
||||
s.add(GradientOklchIncreasing::new, "Gradient - Oklch Increasing");
|
||||
s.add(GradientOklchDecreasing::new, "Gradient - Oklch Decreasing");
|
||||
s.add(GradientOklchAlpha::new, "Gradient - Alpha");
|
||||
|
||||
let content_headerbar = adw::HeaderBar::new();
|
||||
|
||||
|
@ -153,6 +153,7 @@ layout {
|
||||
// The angle is the same as in linear-gradient, and is optional,
|
||||
// defaulting to 180 (top-to-bottom gradient).
|
||||
// You can use any CSS linear-gradient tool on the web to set these up.
|
||||
// Changing the color space is also supported, check the wiki for more info.
|
||||
//
|
||||
// active-gradient from="#80c8ff" to="#bbddff" angle=45
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::iter::zip;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use niri_config::{CornerRadius, Gradient, GradientRelativeTo};
|
||||
use niri_config::{CornerRadius, Gradient, GradientRelativeTo, GradientInterpolation};
|
||||
use smithay::backend::renderer::element::Kind;
|
||||
use smithay::utils::{Logical, Point, Rectangle, Size};
|
||||
|
||||
@ -91,6 +91,7 @@ impl FocusRing {
|
||||
to: color,
|
||||
angle: 0,
|
||||
relative_to: GradientRelativeTo::Window,
|
||||
in_: GradientInterpolation::default()
|
||||
});
|
||||
|
||||
let full_rect = Rectangle::from_loc_and_size((-width, -width), self.full_size);
|
||||
@ -178,6 +179,7 @@ impl FocusRing {
|
||||
border.update(
|
||||
size,
|
||||
Rectangle::from_loc_and_size(gradient_area.loc - loc, gradient_area.size),
|
||||
gradient.in_,
|
||||
gradient.from.into(),
|
||||
gradient.to.into(),
|
||||
((gradient.angle as f32) - 90.).to_radians(),
|
||||
@ -198,6 +200,7 @@ impl FocusRing {
|
||||
gradient_area.loc - self.locations[0],
|
||||
gradient_area.size,
|
||||
),
|
||||
gradient.in_,
|
||||
gradient.from.into(),
|
||||
gradient.to.into(),
|
||||
((gradient.angle as f32) - 90.).to_radians(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use niri_config::CornerRadius;
|
||||
use niri_config::{CornerRadius, GradientInterpolation};
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::{Element, Kind};
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
@ -757,6 +757,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
return BorderRenderElement::new(
|
||||
geo.size,
|
||||
Rectangle::from_loc_and_size((0., 0.), geo.size),
|
||||
GradientInterpolation::default(),
|
||||
elem.color(),
|
||||
elem.color(),
|
||||
0.,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use glam::{Mat3, Vec2};
|
||||
use niri_config::CornerRadius;
|
||||
use niri_config::{CornerRadius, GradientInterpolation, GradientColorSpace, HueInterpolation};
|
||||
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
|
||||
use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer, Uniform};
|
||||
use smithay::backend::renderer::utils::{CommitCounter, DamageSet, OpaqueRegions};
|
||||
@ -28,6 +28,7 @@ pub struct BorderRenderElement {
|
||||
struct Parameters {
|
||||
size: Size<f64, Logical>,
|
||||
gradient_area: Rectangle<f64, Logical>,
|
||||
gradient_format: GradientInterpolation,
|
||||
color_from: [f32; 4],
|
||||
color_to: [f32; 4],
|
||||
angle: f32,
|
||||
@ -43,6 +44,7 @@ impl BorderRenderElement {
|
||||
pub fn new(
|
||||
size: Size<f64, Logical>,
|
||||
gradient_area: Rectangle<f64, Logical>,
|
||||
gradient_format: GradientInterpolation,
|
||||
color_from: [f32; 4],
|
||||
color_to: [f32; 4],
|
||||
angle: f32,
|
||||
@ -57,6 +59,7 @@ impl BorderRenderElement {
|
||||
params: Parameters {
|
||||
size,
|
||||
gradient_area,
|
||||
gradient_format,
|
||||
color_from,
|
||||
color_to,
|
||||
angle,
|
||||
@ -77,6 +80,7 @@ impl BorderRenderElement {
|
||||
params: Parameters {
|
||||
size: Default::default(),
|
||||
gradient_area: Default::default(),
|
||||
gradient_format: GradientInterpolation::default(),
|
||||
color_from: Default::default(),
|
||||
color_to: Default::default(),
|
||||
angle: 0.,
|
||||
@ -97,6 +101,7 @@ impl BorderRenderElement {
|
||||
&mut self,
|
||||
size: Size<f64, Logical>,
|
||||
gradient_area: Rectangle<f64, Logical>,
|
||||
gradient_format: GradientInterpolation,
|
||||
color_from: [f32; 4],
|
||||
color_to: [f32; 4],
|
||||
angle: f32,
|
||||
@ -108,6 +113,7 @@ impl BorderRenderElement {
|
||||
let params = Parameters {
|
||||
size,
|
||||
gradient_area,
|
||||
gradient_format,
|
||||
color_from,
|
||||
color_to,
|
||||
angle,
|
||||
@ -128,6 +134,7 @@ impl BorderRenderElement {
|
||||
let Parameters {
|
||||
size,
|
||||
gradient_area,
|
||||
gradient_format,
|
||||
color_from,
|
||||
color_to,
|
||||
angle,
|
||||
@ -162,11 +169,27 @@ impl BorderRenderElement {
|
||||
let input_to_geo =
|
||||
Mat3::from_scale(area_size) * Mat3::from_translation(-geo_loc / area_size);
|
||||
|
||||
let colorspace = match gradient_format.color_space {
|
||||
GradientColorSpace::Srgb => 0.,
|
||||
GradientColorSpace::SrgbLinear => 1.,
|
||||
GradientColorSpace::Oklab => 2.,
|
||||
GradientColorSpace::Oklch => 3.,
|
||||
};
|
||||
|
||||
let hue_interpolation = match gradient_format.hue_interpol {
|
||||
HueInterpolation::Shorter => 0.,
|
||||
HueInterpolation::Longer => 1.,
|
||||
HueInterpolation::Increasing => 2.,
|
||||
HueInterpolation::Decreasing => 3.,
|
||||
};
|
||||
|
||||
self.inner.update(
|
||||
size,
|
||||
None,
|
||||
scale,
|
||||
vec![
|
||||
Uniform::new("colorspace", colorspace),
|
||||
Uniform::new("hue_interpolation", hue_interpolation),
|
||||
Uniform::new("color_from", color_from),
|
||||
Uniform::new("color_to", color_to),
|
||||
Uniform::new("grad_offset", grad_offset.to_array()),
|
||||
|
@ -10,6 +10,8 @@ uniform float niri_scale;
|
||||
uniform vec2 niri_size;
|
||||
varying vec2 niri_v_coords;
|
||||
|
||||
uniform float colorspace;
|
||||
uniform float hue_interpolation;
|
||||
uniform vec4 color_from;
|
||||
uniform vec4 color_to;
|
||||
uniform vec2 grad_offset;
|
||||
@ -21,6 +23,173 @@ uniform vec2 geo_size;
|
||||
uniform vec4 outer_radius;
|
||||
uniform float border_width;
|
||||
|
||||
float srgb_to_linear(float color) {
|
||||
return pow(color, 2.2);
|
||||
}
|
||||
|
||||
float linear_to_srgb(float color) {
|
||||
return pow(color, 1.0 / 2.2);
|
||||
}
|
||||
|
||||
vec3 lab_to_lch(vec3 color) {
|
||||
float c = sqrt(pow(color.y, 2.0) + pow(color.z, 2.0));
|
||||
float h = degrees(atan(color.z, color.y)) ;
|
||||
h += h <= 0.0 ?
|
||||
360.0 :
|
||||
0.0 ;
|
||||
return vec3(
|
||||
color.x,
|
||||
c,
|
||||
h
|
||||
);
|
||||
}
|
||||
|
||||
vec3 lch_to_lab(vec3 color) {
|
||||
float a = color.y * clamp(cos(radians(color.z)), -1.0, 1.0);
|
||||
float b = color.y * clamp(sin(radians(color.z)), -1.0, 1.0);
|
||||
return vec3(
|
||||
color.x,
|
||||
a,
|
||||
b
|
||||
);
|
||||
}
|
||||
|
||||
vec3 linear_to_oklab(vec3 color){
|
||||
mat3 rgb_to_lms = mat3(
|
||||
vec3(0.4122214708, 0.5363325363, 0.0514459929),
|
||||
vec3(0.2119034982, 0.6806995451, 0.1073969566),
|
||||
vec3(0.0883024619, 0.2817188376, 0.6299787005)
|
||||
);
|
||||
mat3 lms_to_oklab = mat3(
|
||||
vec3(0.2104542553, 0.7936177850, -0.0040720468),
|
||||
vec3(1.9779984951, -2.4285922050, 0.4505937099),
|
||||
vec3(0.0259040371, 0.7827717662, -0.8086757660)
|
||||
);
|
||||
vec3 lms = color * rgb_to_lms;
|
||||
|
||||
lms = vec3(
|
||||
pow(lms.x, 1.0 / 3.0),
|
||||
pow(lms.y, 1.0 / 3.0),
|
||||
pow(lms.z, 1.0 / 3.0)
|
||||
);
|
||||
return lms * lms_to_oklab;
|
||||
}
|
||||
|
||||
vec3 oklab_to_linear(vec3 color){
|
||||
mat3 oklab_to_lms = mat3(
|
||||
vec3(1.0, 0.3963377774, 0.2158037573),
|
||||
vec3(1.0, -0.1055613458, -0.0638541728),
|
||||
vec3(1.0, -0.0894841775, -1.2914855480)
|
||||
);
|
||||
mat3 lms_to_rgb = mat3(
|
||||
vec3(4.0767416621, -3.3077115913, 0.2309699292),
|
||||
vec3(-1.2684380046, 2.6097574011, -0.3413193965),
|
||||
vec3(-0.0041960863, -0.7034186147, 1.7076147010)
|
||||
);
|
||||
vec3 lms = color * oklab_to_lms;
|
||||
|
||||
lms = vec3(
|
||||
pow(lms.x, 3.0),
|
||||
pow(lms.y, 3.0),
|
||||
pow(lms.z, 3.0)
|
||||
);
|
||||
return lms * lms_to_rgb;
|
||||
}
|
||||
|
||||
vec4 color_mix(vec4 color1, vec4 color2, float color_ratio) {
|
||||
// srgb
|
||||
|
||||
vec4 color_out;
|
||||
|
||||
if (colorspace == 0.0) {
|
||||
color_out = mix(color1, color2, color_ratio);
|
||||
color_out.rgb = color_out.rgb * color_out.a;
|
||||
return color_out;
|
||||
}
|
||||
|
||||
color1.rgb = vec3(
|
||||
srgb_to_linear(color1.r),
|
||||
srgb_to_linear(color1.g),
|
||||
srgb_to_linear(color1.b)
|
||||
);
|
||||
color2.rgb = vec3(
|
||||
srgb_to_linear(color2.r),
|
||||
srgb_to_linear(color2.g),
|
||||
srgb_to_linear(color2.b)
|
||||
);
|
||||
// srgb-linear
|
||||
if (colorspace == 1.0) {
|
||||
color_out = mix(
|
||||
color1,
|
||||
color2,
|
||||
color_ratio
|
||||
);
|
||||
// oklab
|
||||
} else if (colorspace == 2.0) {
|
||||
color1.xyz = linear_to_oklab(color1.rgb);
|
||||
color2.xyz = linear_to_oklab(color2.rgb);
|
||||
color_out = mix(
|
||||
color1,
|
||||
color2,
|
||||
color_ratio
|
||||
);
|
||||
color_out.rgb = oklab_to_linear(color_out.xyz);
|
||||
// oklch
|
||||
} else if (colorspace == 3.0) {
|
||||
color1.xyz = lab_to_lch(linear_to_oklab(color1.rgb));
|
||||
color2.xyz = lab_to_lch(linear_to_oklab(color2.rgb));
|
||||
color_out = mix(color1, color2, color_ratio);
|
||||
|
||||
float min_hue = min(color1.z, color2.z);
|
||||
float max_hue = max(color1.z, color2.z);
|
||||
float path_direct_distance = (max_hue - min_hue) * color_ratio;
|
||||
float path_mod_distance = (360.0 - max_hue + min_hue) * color_ratio;
|
||||
|
||||
float path_mod =
|
||||
color1.z == min_hue ?
|
||||
mod(color1.z - path_mod_distance, 360.0) :
|
||||
mod(color1.z + path_mod_distance, 360.0) ;
|
||||
float path_direct =
|
||||
color1.z == min_hue ?
|
||||
color1.z + path_direct_distance :
|
||||
color1.z - path_direct_distance ;
|
||||
|
||||
// shorter
|
||||
if (hue_interpolation == 0.0) {
|
||||
color_out.z =
|
||||
max_hue - min_hue > 360.0 - max_hue + min_hue ?
|
||||
path_mod :
|
||||
path_direct ;
|
||||
// longer
|
||||
} else if (hue_interpolation == 1.0) {
|
||||
color_out.z =
|
||||
max_hue - min_hue <= 360.0 - max_hue + min_hue ?
|
||||
path_mod :
|
||||
path_direct ;
|
||||
// increasing
|
||||
} else if (hue_interpolation == 2.0) {
|
||||
color_out.z =
|
||||
color1.z > color2.z ?
|
||||
path_mod :
|
||||
path_direct ;
|
||||
// decreasing
|
||||
} else if (hue_interpolation == 3.0) {
|
||||
color_out.z =
|
||||
color1.z <= color2.z ?
|
||||
path_mod :
|
||||
path_direct ;
|
||||
}
|
||||
color_out.rgb = clamp(oklab_to_linear(lch_to_lab(color_out.xyz)), 0.0, 1.0);
|
||||
}
|
||||
|
||||
return vec4(
|
||||
linear_to_srgb(color_out.r) * color_out.a,
|
||||
linear_to_srgb(color_out.g) * color_out.a,
|
||||
linear_to_srgb(color_out.b) * color_out.a,
|
||||
color_out.a
|
||||
);
|
||||
}
|
||||
|
||||
vec4 gradient_color(vec2 coords) {
|
||||
coords = coords + grad_offset;
|
||||
|
||||
@ -33,7 +202,7 @@ vec4 gradient_color(vec2 coords) {
|
||||
frac += 1.0;
|
||||
|
||||
frac = clamp(frac, 0.0, 1.0);
|
||||
return mix(color_from, color_to, frac);
|
||||
return color_mix(color_from, color_to, frac);
|
||||
}
|
||||
|
||||
float rounding_alpha(vec2 coords, vec2 size, vec4 corner_radius) {
|
||||
|
@ -34,6 +34,8 @@ impl Shaders {
|
||||
renderer,
|
||||
include_str!("border.frag"),
|
||||
&[
|
||||
UniformName::new("colorspace", UniformType::_1f),
|
||||
UniformName::new("hue_interpolation", UniformType::_1f),
|
||||
UniformName::new("color_from", UniformType::_4f),
|
||||
UniformName::new("color_to", UniformType::_4f),
|
||||
UniformName::new("grad_offset", UniformType::_2f),
|
||||
|
@ -2,7 +2,7 @@ use std::cell::{Cell, RefCell};
|
||||
use std::cmp::{max, min};
|
||||
use std::time::Duration;
|
||||
|
||||
use niri_config::{CornerRadius, WindowRule};
|
||||
use niri_config::{CornerRadius, GradientInterpolation, WindowRule};
|
||||
use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;
|
||||
use smithay::backend::renderer::element::{Id, Kind};
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
@ -289,6 +289,7 @@ impl Mapped {
|
||||
return BorderRenderElement::new(
|
||||
geo.size,
|
||||
Rectangle::from_loc_and_size((0., 0.), geo.size),
|
||||
GradientInterpolation::default(),
|
||||
elem.color(),
|
||||
elem.color(),
|
||||
0.,
|
||||
|
@ -32,7 +32,7 @@ layout {
|
||||
active-color "#ffc87f"
|
||||
inactive-color "#505050"
|
||||
// active-gradient from="#ffbb66" to="#ffc880" angle=45 relative-to="workspace-view"
|
||||
// inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view"
|
||||
// inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view" in="srgb-linear"
|
||||
}
|
||||
|
||||
struts {
|
||||
@ -169,7 +169,7 @@ layout {
|
||||
inactive-color "#505050"
|
||||
|
||||
// active-gradient from="#ffbb66" to="#ffc880" angle=45 relative-to="workspace-view"
|
||||
// inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view"
|
||||
// inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view" in="srgb-linear"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -221,6 +221,9 @@ layout {
|
||||
}
|
||||
```
|
||||
|
||||
Gradients can be rendered with different kinds of color interpolation, this doesen't mean that the arguments the gradient takes are any different.
|
||||
Except for an optional `in` argument which can take both a colorspace and a hue interpolation method if the color space is polar.
|
||||
|
||||
Gradients can be colored relative to windows individually (the default), or to the whole view of the workspace.
|
||||
To do that, set `relative-to="workspace-view"`.
|
||||
Here's a visual example:
|
||||
|
Loading…
Reference in New Issue
Block a user