aboutsummaryrefslogtreecommitdiff
path: root/niri-config/src/lib.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-08-27 10:31:14 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-08-27 10:46:46 +0300
commit02e3f9f66ee71ce5252df3bb7b7c9743e95fdcbc (patch)
tree788579ba0374a25e26782c80f332469b5c8724a8 /niri-config/src/lib.rs
parent19c576cfd88fa58c8f3e8123933e8a13ba6da3fa (diff)
downloadniri-02e3f9f66ee71ce5252df3bb7b7c9743e95fdcbc.tar.gz
niri-02e3f9f66ee71ce5252df3bb7b7c9743e95fdcbc.tar.bz2
niri-02e3f9f66ee71ce5252df3bb7b7c9743e95fdcbc.zip
config: Extract appearance and layout
Diffstat (limited to 'niri-config/src/lib.rs')
-rw-r--r--niri-config/src/lib.rs1267
1 files changed, 8 insertions, 1259 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index 35789be2..0de753f7 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -5,7 +5,6 @@ use std::collections::HashSet;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::Write;
-use std::ops::{Mul, MulAssign};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
@@ -16,17 +15,15 @@ use miette::{miette, Context, IntoDiagnostic};
use niri_ipc::{
ColumnDisplay, LayoutSwitchTarget, PositionChange, SizeChange, WorkspaceReferenceArg,
};
-use smithay::backend::renderer::Color32F;
use smithay::input::keyboard::keysyms::KEY_NoSymbol;
use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE};
use smithay::input::keyboard::Keysym;
-pub const DEFAULT_BACKGROUND_COLOR: Color = Color::from_array_unpremul([0.25, 0.25, 0.25, 1.]);
-pub const DEFAULT_BACKDROP_COLOR: Color = Color::from_array_unpremul([0.15, 0.15, 0.15, 1.]);
-
pub mod animations;
+pub mod appearance;
pub mod input;
pub mod layer_rule;
+pub mod layout;
pub mod output;
pub mod utils;
pub mod window_rule;
@@ -34,8 +31,10 @@ pub mod window_rule;
pub use crate::animations::{
Animation, AnimationCurve, AnimationKind, Animations, EasingParams, SpringParams,
};
+pub use crate::appearance::*;
pub use crate::input::{Input, ModKey, ScrollMethod, TrackLayout, WarpMouseToFocusMode, Xkb};
pub use crate::layer_rule::LayerRule;
+pub use crate::layout::*;
pub use crate::output::{Output, OutputName, Outputs, Position, Vrr};
pub use crate::window_rule::{FloatingPosition, RelativeTo, WindowRule};
@@ -93,18 +92,6 @@ pub struct Config {
pub workspaces: Vec<Workspace>,
}
-#[derive(knuffel::DecodeScalar, Debug, Default, PartialEq, Eq, Clone, Copy)]
-pub enum CenterFocusedColumn {
- /// Focusing a column will not center the column.
- #[default]
- Never,
- /// The focused column will always be centered.
- Always,
- /// Focusing a column will center it if it doesn't fit on the screen together with the
- /// previously focused column.
- OnOverflow,
-}
-
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Percent(pub f64);
@@ -112,62 +99,6 @@ pub struct Percent(pub f64);
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct FloatOrInt<const MIN: i32, const MAX: i32>(pub f64);
-#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
-pub struct Layout {
- #[knuffel(child, default)]
- pub focus_ring: FocusRing,
- #[knuffel(child, default)]
- pub border: Border,
- #[knuffel(child, default)]
- pub shadow: Shadow,
- #[knuffel(child, default)]
- pub tab_indicator: TabIndicator,
- #[knuffel(child, default)]
- pub insert_hint: InsertHint,
- #[knuffel(child, unwrap(children), default)]
- pub preset_column_widths: Vec<PresetSize>,
- #[knuffel(child)]
- pub default_column_width: Option<DefaultPresetSize>,
- #[knuffel(child, unwrap(children), default)]
- pub preset_window_heights: Vec<PresetSize>,
- #[knuffel(child, unwrap(argument), default)]
- pub center_focused_column: CenterFocusedColumn,
- #[knuffel(child)]
- pub always_center_single_column: bool,
- #[knuffel(child)]
- pub empty_workspace_above_first: bool,
- #[knuffel(child, unwrap(argument, str), default = Self::default().default_column_display)]
- pub default_column_display: ColumnDisplay,
- #[knuffel(child, unwrap(argument), default = Self::default().gaps)]
- pub gaps: FloatOrInt<0, 65535>,
- #[knuffel(child, default)]
- pub struts: Struts,
- #[knuffel(child, default = DEFAULT_BACKGROUND_COLOR)]
- pub background_color: Color,
-}
-
-impl Default for Layout {
- fn default() -> Self {
- Self {
- focus_ring: Default::default(),
- border: Default::default(),
- shadow: Default::default(),
- tab_indicator: Default::default(),
- insert_hint: Default::default(),
- preset_column_widths: Default::default(),
- default_column_width: Default::default(),
- center_focused_column: Default::default(),
- always_center_single_column: false,
- empty_workspace_above_first: false,
- default_column_display: ColumnDisplay::Normal,
- gaps: FloatOrInt(16.),
- struts: Default::default(),
- preset_window_heights: Default::default(),
- background_color: DEFAULT_BACKGROUND_COLOR,
- }
- }
-}
-
#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
pub struct SpawnAtStartup {
#[knuffel(arguments)]
@@ -180,407 +111,6 @@ pub struct SpawnShAtStartup {
pub command: String,
}
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct FocusRing {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child, unwrap(argument), default = Self::default().width)]
- pub width: FloatOrInt<0, 65535>,
- #[knuffel(child, default = Self::default().active_color)]
- pub active_color: Color,
- #[knuffel(child, default = Self::default().inactive_color)]
- pub inactive_color: Color,
- #[knuffel(child, default = Self::default().urgent_color)]
- pub urgent_color: Color,
- #[knuffel(child)]
- pub active_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub inactive_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub urgent_gradient: Option<Gradient>,
-}
-
-impl Default for FocusRing {
- fn default() -> Self {
- Self {
- off: false,
- width: FloatOrInt(4.),
- active_color: Color::from_rgba8_unpremul(127, 200, 255, 255),
- inactive_color: Color::from_rgba8_unpremul(80, 80, 80, 255),
- urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
- active_gradient: None,
- inactive_gradient: None,
- urgent_gradient: None,
- }
- }
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct Gradient {
- #[knuffel(property, str)]
- pub from: Color,
- #[knuffel(property, str)]
- pub to: Color,
- #[knuffel(property, default = 180)]
- pub angle: i16,
- #[knuffel(property, default)]
- pub relative_to: GradientRelativeTo,
- #[knuffel(property(name = "in"), str, default)]
- pub in_: GradientInterpolation,
-}
-
-impl From<Color> for Gradient {
- fn from(value: Color) -> Self {
- Self {
- from: value,
- to: value,
- angle: 0,
- relative_to: GradientRelativeTo::Window,
- in_: GradientInterpolation::default(),
- }
- }
-}
-
-#[derive(knuffel::DecodeScalar, Debug, Default, Clone, Copy, PartialEq, Eq)]
-pub enum GradientRelativeTo {
- #[default]
- Window,
- WorkspaceView,
-}
-
-#[derive(Default, Debug, Clone, Copy, PartialEq)]
-pub struct GradientInterpolation {
- pub color_space: GradientColorSpace,
- pub hue_interpolation: 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)]
- pub off: bool,
- #[knuffel(child, unwrap(argument), default = Self::default().width)]
- pub width: FloatOrInt<0, 65535>,
- #[knuffel(child, default = Self::default().active_color)]
- pub active_color: Color,
- #[knuffel(child, default = Self::default().inactive_color)]
- pub inactive_color: Color,
- #[knuffel(child, default = Self::default().urgent_color)]
- pub urgent_color: Color,
- #[knuffel(child)]
- pub active_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub inactive_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub urgent_gradient: Option<Gradient>,
-}
-
-impl Default for Border {
- fn default() -> Self {
- Self {
- off: true,
- width: FloatOrInt(4.),
- active_color: Color::from_rgba8_unpremul(255, 200, 127, 255),
- inactive_color: Color::from_rgba8_unpremul(80, 80, 80, 255),
- urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
- active_gradient: None,
- inactive_gradient: None,
- urgent_gradient: None,
- }
- }
-}
-
-impl From<Border> for FocusRing {
- fn from(value: Border) -> Self {
- Self {
- off: value.off,
- width: value.width,
- active_color: value.active_color,
- inactive_color: value.inactive_color,
- urgent_color: value.urgent_color,
- active_gradient: value.active_gradient,
- inactive_gradient: value.inactive_gradient,
- urgent_gradient: value.urgent_gradient,
- }
- }
-}
-
-impl From<FocusRing> for Border {
- fn from(value: FocusRing) -> Self {
- Self {
- off: value.off,
- width: value.width,
- active_color: value.active_color,
- inactive_color: value.inactive_color,
- urgent_color: value.urgent_color,
- active_gradient: value.active_gradient,
- inactive_gradient: value.inactive_gradient,
- urgent_gradient: value.urgent_gradient,
- }
- }
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct Shadow {
- #[knuffel(child)]
- pub on: bool,
- #[knuffel(child, default = Self::default().offset)]
- pub offset: ShadowOffset,
- #[knuffel(child, unwrap(argument), default = Self::default().softness)]
- pub softness: FloatOrInt<0, 1024>,
- #[knuffel(child, unwrap(argument), default = Self::default().spread)]
- pub spread: FloatOrInt<-1024, 1024>,
- #[knuffel(child, unwrap(argument), default = Self::default().draw_behind_window)]
- pub draw_behind_window: bool,
- #[knuffel(child, default = Self::default().color)]
- pub color: Color,
- #[knuffel(child)]
- pub inactive_color: Option<Color>,
-}
-
-impl Default for Shadow {
- fn default() -> Self {
- Self {
- on: false,
- offset: ShadowOffset {
- x: FloatOrInt(0.),
- y: FloatOrInt(5.),
- },
- softness: FloatOrInt(30.),
- spread: FloatOrInt(5.),
- draw_behind_window: false,
- color: Color::from_rgba8_unpremul(0, 0, 0, 0x70),
- inactive_color: None,
- }
- }
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct ShadowOffset {
- #[knuffel(property, default)]
- pub x: FloatOrInt<-65535, 65535>,
- #[knuffel(property, default)]
- pub y: FloatOrInt<-65535, 65535>,
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct WorkspaceShadow {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child, default = Self::default().offset)]
- pub offset: ShadowOffset,
- #[knuffel(child, unwrap(argument), default = Self::default().softness)]
- pub softness: FloatOrInt<0, 1024>,
- #[knuffel(child, unwrap(argument), default = Self::default().spread)]
- pub spread: FloatOrInt<-1024, 1024>,
- #[knuffel(child, default = Self::default().color)]
- pub color: Color,
-}
-
-impl Default for WorkspaceShadow {
- fn default() -> Self {
- Self {
- off: false,
- offset: ShadowOffset {
- x: FloatOrInt(0.),
- y: FloatOrInt(10.),
- },
- softness: FloatOrInt(40.),
- spread: FloatOrInt(10.),
- color: Color::from_rgba8_unpremul(0, 0, 0, 0x50),
- }
- }
-}
-
-impl From<WorkspaceShadow> for Shadow {
- fn from(value: WorkspaceShadow) -> Self {
- Self {
- on: !value.off,
- offset: value.offset,
- softness: value.softness,
- spread: value.spread,
- draw_behind_window: false,
- color: value.color,
- inactive_color: None,
- }
- }
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct TabIndicator {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child)]
- pub hide_when_single_tab: bool,
- #[knuffel(child)]
- pub place_within_column: bool,
- #[knuffel(child, unwrap(argument), default = Self::default().gap)]
- pub gap: FloatOrInt<-65535, 65535>,
- #[knuffel(child, unwrap(argument), default = Self::default().width)]
- pub width: FloatOrInt<0, 65535>,
- #[knuffel(child, default = Self::default().length)]
- pub length: TabIndicatorLength,
- #[knuffel(child, unwrap(argument), default = Self::default().position)]
- pub position: TabIndicatorPosition,
- #[knuffel(child, unwrap(argument), default = Self::default().gaps_between_tabs)]
- pub gaps_between_tabs: FloatOrInt<0, 65535>,
- #[knuffel(child, unwrap(argument), default = Self::default().corner_radius)]
- pub corner_radius: FloatOrInt<0, 65535>,
- #[knuffel(child)]
- pub active_color: Option<Color>,
- #[knuffel(child)]
- pub inactive_color: Option<Color>,
- #[knuffel(child)]
- pub urgent_color: Option<Color>,
- #[knuffel(child)]
- pub active_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub inactive_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub urgent_gradient: Option<Gradient>,
-}
-
-impl Default for TabIndicator {
- fn default() -> Self {
- Self {
- off: false,
- hide_when_single_tab: false,
- place_within_column: false,
- gap: FloatOrInt(5.),
- width: FloatOrInt(4.),
- length: TabIndicatorLength {
- total_proportion: Some(0.5),
- },
- position: TabIndicatorPosition::Left,
- gaps_between_tabs: FloatOrInt(0.),
- corner_radius: FloatOrInt(0.),
- active_color: None,
- inactive_color: None,
- urgent_color: None,
- active_gradient: None,
- inactive_gradient: None,
- urgent_gradient: None,
- }
- }
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct TabIndicatorLength {
- #[knuffel(property)]
- pub total_proportion: Option<f64>,
-}
-
-#[derive(knuffel::DecodeScalar, Debug, Clone, Copy, PartialEq)]
-pub enum TabIndicatorPosition {
- Left,
- Right,
- Top,
- Bottom,
-}
-
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub struct InsertHint {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child, default = Self::default().color)]
- pub color: Color,
- #[knuffel(child)]
- pub gradient: Option<Gradient>,
-}
-
-impl Default for InsertHint {
- fn default() -> Self {
- Self {
- off: false,
- color: Color::from_rgba8_unpremul(127, 200, 255, 128),
- gradient: None,
- }
- }
-}
-
-/// RGB color in [0, 1] with unpremultiplied alpha.
-#[derive(Debug, Default, Clone, Copy, PartialEq)]
-pub struct Color {
- pub r: f32,
- pub g: f32,
- pub b: f32,
- pub a: f32,
-}
-
-impl Color {
- pub const fn new_unpremul(r: f32, g: f32, b: f32, a: f32) -> Self {
- Self { r, g, b, a }
- }
-
- pub fn from_rgba8_unpremul(r: u8, g: u8, b: u8, a: u8) -> Self {
- Self::from_array_unpremul([r, g, b, a].map(|x| x as f32 / 255.))
- }
-
- pub fn from_array_premul([r, g, b, a]: [f32; 4]) -> Self {
- let a = a.clamp(0., 1.);
-
- if a == 0. {
- Self::new_unpremul(0., 0., 0., 0.)
- } else {
- Self {
- r: (r / a).clamp(0., 1.),
- g: (g / a).clamp(0., 1.),
- b: (b / a).clamp(0., 1.),
- a,
- }
- }
- }
-
- pub const fn from_array_unpremul([r, g, b, a]: [f32; 4]) -> Self {
- Self { r, g, b, a }
- }
-
- pub fn from_color32f(color: Color32F) -> Self {
- Self::from_array_premul(color.components())
- }
-
- pub fn to_array_unpremul(self) -> [f32; 4] {
- [self.r, self.g, self.b, self.a]
- }
-
- pub fn to_array_premul(self) -> [f32; 4] {
- let [r, g, b, a] = [self.r, self.g, self.b, self.a];
- [r * a, g * a, b * a, a]
- }
-}
-
-impl Mul<f32> for Color {
- type Output = Self;
-
- fn mul(mut self, rhs: f32) -> Self::Output {
- self.a *= rhs;
- self
- }
-}
-
-impl MulAssign<f32> for Color {
- fn mul_assign(&mut self, rhs: f32) {
- self.a *= rhs;
- }
-}
-
#[derive(knuffel::Decode, Debug, PartialEq)]
pub struct Cursor {
#[knuffel(child, unwrap(argument), default = String::from("default"))]
@@ -604,36 +134,6 @@ impl Default for Cursor {
}
}
-#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
-pub enum PresetSize {
- Proportion(#[knuffel(argument)] f64),
- Fixed(#[knuffel(argument)] i32),
-}
-
-impl From<PresetSize> for SizeChange {
- fn from(value: PresetSize) -> Self {
- match value {
- PresetSize::Proportion(prop) => SizeChange::SetProportion(prop * 100.),
- PresetSize::Fixed(fixed) => SizeChange::SetFixed(fixed),
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct DefaultPresetSize(pub Option<PresetSize>);
-
-#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
-pub struct Struts {
- #[knuffel(child, unwrap(argument), default)]
- pub left: FloatOrInt<-65535, 65535>,
- #[knuffel(child, unwrap(argument), default)]
- pub right: FloatOrInt<-65535, 65535>,
- #[knuffel(child, unwrap(argument), default)]
- pub top: FloatOrInt<-65535, 65535>,
- #[knuffel(child, unwrap(argument), default)]
- pub bottom: FloatOrInt<-65535, 65535>,
-}
-
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct HotkeyOverlay {
#[knuffel(child)]
@@ -717,15 +217,15 @@ pub struct Overview {
#[knuffel(child, default = Self::default().backdrop_color)]
pub backdrop_color: Color,
#[knuffel(child, default)]
- pub workspace_shadow: WorkspaceShadow,
+ pub workspace_shadow: appearance::WorkspaceShadow,
}
impl Default for Overview {
fn default() -> Self {
Self {
zoom: FloatOrInt(0.5),
- backdrop_color: DEFAULT_BACKDROP_COLOR,
- workspace_shadow: WorkspaceShadow::default(),
+ backdrop_color: appearance::DEFAULT_BACKDROP_COLOR,
+ workspace_shadow: appearance::WorkspaceShadow::default(),
}
}
}
@@ -769,100 +269,6 @@ pub struct Workspace {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkspaceName(pub String);
-#[derive(Debug, Default, Clone, Copy, PartialEq)]
-pub struct CornerRadius {
- pub top_left: f32,
- pub top_right: f32,
- pub bottom_right: f32,
- pub bottom_left: f32,
-}
-
-impl From<CornerRadius> for [f32; 4] {
- fn from(value: CornerRadius) -> Self {
- [
- value.top_left,
- value.top_right,
- value.bottom_right,
- value.bottom_left,
- ]
- }
-}
-
-impl From<f32> for CornerRadius {
- fn from(value: f32) -> Self {
- Self {
- top_left: value,
- top_right: value,
- bottom_right: value,
- bottom_left: value,
- }
- }
-}
-
-#[derive(knuffel::DecodeScalar, Debug, Clone, Copy, PartialEq, Eq)]
-pub enum BlockOutFrom {
- Screencast,
- ScreenCapture,
-}
-
-#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
-pub struct BorderRule {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child)]
- pub on: bool,
- #[knuffel(child, unwrap(argument))]
- pub width: Option<FloatOrInt<0, 65535>>,
- #[knuffel(child)]
- pub active_color: Option<Color>,
- #[knuffel(child)]
- pub inactive_color: Option<Color>,
- #[knuffel(child)]
- pub urgent_color: Option<Color>,
- #[knuffel(child)]
- pub active_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub inactive_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub urgent_gradient: Option<Gradient>,
-}
-
-#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
-pub struct ShadowRule {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child)]
- pub on: bool,
- #[knuffel(child)]
- pub offset: Option<ShadowOffset>,
- #[knuffel(child, unwrap(argument))]
- pub softness: Option<FloatOrInt<0, 1024>>,
- #[knuffel(child, unwrap(argument))]
- pub spread: Option<FloatOrInt<-1024, 1024>>,
- #[knuffel(child, unwrap(argument))]
- pub draw_behind_window: Option<bool>,
- #[knuffel(child)]
- pub color: Option<Color>,
- #[knuffel(child)]
- pub inactive_color: Option<Color>,
-}
-
-#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
-pub struct TabIndicatorRule {
- #[knuffel(child)]
- pub active_color: Option<Color>,
- #[knuffel(child)]
- pub inactive_color: Option<Color>,
- #[knuffel(child)]
- pub urgent_color: Option<Color>,
- #[knuffel(child)]
- pub active_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub inactive_gradient: Option<Gradient>,
- #[knuffel(child)]
- pub urgent_gradient: Option<Gradient>,
-}
-
#[derive(Debug, Default, PartialEq)]
pub struct Binds(pub Vec<Bind>);
@@ -1776,383 +1182,6 @@ impl Default for Config {
}
}
-impl BorderRule {
- pub fn merge_with(&mut self, other: &Self) {
- if other.off {
- self.off = true;
- self.on = false;
- }
-
- if other.on {
- self.off = false;
- self.on = true;
- }
-
- if let Some(x) = other.width {
- self.width = Some(x);
- }
- if let Some(x) = other.active_color {
- self.active_color = Some(x);
- }
- if let Some(x) = other.inactive_color {
- self.inactive_color = Some(x);
- }
- if let Some(x) = other.urgent_color {
- self.urgent_color = Some(x);
- }
- if let Some(x) = other.active_gradient {
- self.active_gradient = Some(x);
- }
- if let Some(x) = other.inactive_gradient {
- self.inactive_gradient = Some(x);
- }
- if let Some(x) = other.urgent_gradient {
- self.urgent_gradient = Some(x);
- }
- }
-
- pub fn resolve_against(&self, mut config: Border) -> Border {
- config.off |= self.off;
- if self.on {
- config.off = false;
- }
-
- if let Some(x) = self.width {
- config.width = x;
- }
- if let Some(x) = self.active_color {
- config.active_color = x;
- config.active_gradient = None;
- }
- if let Some(x) = self.inactive_color {
- config.inactive_color = x;
- config.inactive_gradient = None;
- }
- if let Some(x) = self.urgent_color {
- config.urgent_color = x;
- config.urgent_gradient = None;
- }
- if let Some(x) = self.active_gradient {
- config.active_gradient = Some(x);
- }
- if let Some(x) = self.inactive_gradient {
- config.inactive_gradient = Some(x);
- }
- if let Some(x) = self.urgent_gradient {
- config.urgent_gradient = Some(x);
- }
-
- config
- }
-}
-
-impl ShadowRule {
- pub fn merge_with(&mut self, other: &Self) {
- if other.off {
- self.off = true;
- self.on = false;
- }
-
- if other.on {
- self.off = false;
- self.on = true;
- }
-
- if let Some(x) = other.offset {
- self.offset = Some(x);
- }
- if let Some(x) = other.softness {
- self.softness = Some(x);
- }
- if let Some(x) = other.spread {
- self.spread = Some(x);
- }
- if let Some(x) = other.draw_behind_window {
- self.draw_behind_window = Some(x);
- }
- if let Some(x) = other.color {
- self.color = Some(x);
- }
- if let Some(x) = other.inactive_color {
- self.inactive_color = Some(x);
- }
- }
-
- pub fn resolve_against(&self, mut config: Shadow) -> Shadow {
- config.on |= self.on;
- if self.off {
- config.on = false;
- }
-
- if let Some(x) = self.offset {
- config.offset = x;
- }
- if let Some(x) = self.softness {
- config.softness = x;
- }
- if let Some(x) = self.spread {
- config.spread = x;
- }
- if let Some(x) = self.draw_behind_window {
- config.draw_behind_window = x;
- }
- if let Some(x) = self.color {
- config.color = x;
- }
- if let Some(x) = self.inactive_color {
- config.inactive_color = Some(x);
- }
-
- config
- }
-}
-
-impl TabIndicatorRule {
- pub fn merge_with(&mut self, other: &Self) {
- if let Some(x) = other.active_color {
- self.active_color = Some(x);
- }
- if let Some(x) = other.inactive_color {
- self.inactive_color = Some(x);
- }
- if let Some(x) = other.urgent_color {
- self.urgent_color = Some(x);
- }
- if let Some(x) = other.active_gradient {
- self.active_gradient = Some(x);
- }
- if let Some(x) = other.inactive_gradient {
- self.inactive_gradient = Some(x);
- }
- if let Some(x) = other.urgent_gradient {
- self.urgent_gradient = Some(x);
- }
- }
-}
-
-impl CornerRadius {
- pub fn fit_to(self, width: f32, height: f32) -> Self {
- // Like in CSS: https://drafts.csswg.org/css-backgrounds/#corner-overlap
- let reduction = f32::min(
- f32::min(
- width / (self.top_left + self.top_right),
- width / (self.bottom_left + self.bottom_right),
- ),
- f32::min(
- height / (self.top_left + self.bottom_left),
- height / (self.top_right + self.bottom_right),
- ),
- );
- let reduction = f32::min(1., reduction);
-
- Self {
- top_left: self.top_left * reduction,
- top_right: self.top_right * reduction,
- bottom_right: self.bottom_right * reduction,
- bottom_left: self.bottom_left * reduction,
- }
- }
-
- pub fn expanded_by(mut self, width: f32) -> Self {
- // Radius = 0 is preserved, so that square corners remain square.
- if self.top_left > 0. {
- self.top_left += width;
- }
- if self.top_right > 0. {
- self.top_right += width;
- }
- if self.bottom_right > 0. {
- self.bottom_right += width;
- }
- if self.bottom_left > 0. {
- self.bottom_left += width;
- }
-
- if width < 0. {
- self.top_left = self.top_left.max(0.);
- self.top_right = self.top_right.max(0.);
- self.bottom_left = self.bottom_left.max(0.);
- self.bottom_right = self.bottom_right.max(0.);
- }
-
- self
- }
-
- pub fn scaled_by(self, scale: f32) -> Self {
- Self {
- top_left: self.top_left * scale,
- top_right: self.top_right * scale,
- bottom_right: self.bottom_right * scale,
- bottom_left: self.bottom_left * scale,
- }
- }
-}
-
-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 Some(in_part1) = in_part1 else {
- return Err(miette!("missing color space"));
- };
-
- let color = match in_part1 {
- "srgb" => GradientColorSpace::Srgb,
- "srgb-linear" => GradientColorSpace::SrgbLinear,
- "oklab" => GradientColorSpace::Oklab,
- "oklch" => GradientColorSpace::Oklch,
- x => {
- return Err(miette!(
- "invalid color space {x}; can be srgb, srgb-linear, oklab or oklch"
- ))
- }
- };
-
- let interpolation = if let Some(in_part2) = in_part2 {
- if color != GradientColorSpace::Oklch {
- return Err(miette!("only oklch color space can have hue interpolation"));
- }
-
- if in_part3 != Some("hue") {
- return Err(miette!(
- "interpolation must end with \"hue\", like \"oklch shorter hue\""
- ));
- } else if iter.next().is_some() {
- return Err(miette!("unexpected text after hue interpolation"));
- } else {
- match in_part2 {
- "shorter" => HueInterpolation::Shorter,
- "longer" => HueInterpolation::Longer,
- "increasing" => HueInterpolation::Increasing,
- "decreasing" => HueInterpolation::Decreasing,
- x => {
- return Err(miette!(
- "invalid hue interpolation {x}; \
- can be shorter, longer, increasing, decreasing"
- ))
- }
- }
- }
- } else {
- HueInterpolation::default()
- };
-
- Ok(Self {
- color_space: color,
- hue_interpolation: interpolation,
- })
- }
-}
-
-impl FromStr for Color {
- type Err = miette::Error;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let color = csscolorparser::parse(s)
- .into_diagnostic()?
- .clamp()
- .to_array();
- Ok(Self::from_array_unpremul(color))
- }
-}
-
-#[derive(knuffel::Decode)]
-struct ColorRgba {
- #[knuffel(argument)]
- r: u8,
- #[knuffel(argument)]
- g: u8,
- #[knuffel(argument)]
- b: u8,
- #[knuffel(argument)]
- a: u8,
-}
-
-impl From<ColorRgba> for Color {
- fn from(value: ColorRgba) -> Self {
- let ColorRgba { r, g, b, a } = value;
- Self::from_array_unpremul([r, g, b, a].map(|x| x as f32 / 255.))
- }
-}
-
-// Manual impl to allow both one-argument string and 4-argument RGBA forms.
-impl<S> knuffel::Decode<S> for Color
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- // Check for unexpected type name.
- if let Some(type_name) = &node.type_name {
- ctx.emit_error(DecodeError::unexpected(
- type_name,
- "type name",
- "no type name expected for this node",
- ));
- }
-
- // Get the first argument.
- let mut iter_args = node.arguments.iter();
- let val = iter_args
- .next()
- .ok_or_else(|| DecodeError::missing(node, "additional argument is required"))?;
-
- // Check for unexpected type name.
- if let Some(typ) = &val.type_name {
- ctx.emit_error(DecodeError::TypeName {
- span: typ.span().clone(),
- found: Some((**typ).clone()),
- expected: knuffel::errors::ExpectedType::no_type(),
- rust_type: "str",
- });
- }
-
- // Check the argument type.
- let rv = match *val.literal {
- // If it's a string, use FromStr.
- knuffel::ast::Literal::String(ref s) => {
- Color::from_str(s).map_err(|e| DecodeError::conversion(&val.literal, e))
- }
- // Otherwise, fall back to the 4-argument RGBA form.
- _ => return ColorRgba::decode_node(node, ctx).map(Color::from),
- }?;
-
- // Check for unexpected following arguments.
- if let Some(val) = iter_args.next() {
- ctx.emit_error(DecodeError::unexpected(
- &val.literal,
- "argument",
- "unexpected argument",
- ));
- }
-
- // Check for unexpected properties and children.
- for name in node.properties.keys() {
- ctx.emit_error(DecodeError::unexpected(
- name,
- "property",
- format!("unexpected property `{}`", name.escape_default()),
- ));
- }
- for child in node.children.as_ref().map(|lst| &lst[..]).unwrap_or(&[]) {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- format!("unexpected node `{}`", child.node_name.escape_default()),
- ));
- }
-
- Ok(rv)
- }
-}
-
fn expect_only_children<S>(
node: &knuffel::ast::SpannedNode<S>,
ctx: &mut knuffel::decode::Context<S>,
@@ -2184,33 +1213,6 @@ fn expect_only_children<S>(
}
}
-impl<S> knuffel::Decode<S> for DefaultPresetSize
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- expect_on