mirror of
https://github.com/YaLTeR/niri.git
synced 2025-10-05 16:12:47 +02:00
config: Split Layout from LayoutPart
This commit is contained in:
@@ -5,7 +5,7 @@ use knuffel::errors::DecodeError;
|
||||
use miette::{miette, IntoDiagnostic as _};
|
||||
use smithay::backend::renderer::Color32F;
|
||||
|
||||
use crate::utils::MergeWith;
|
||||
use crate::utils::{Flag, MergeWith};
|
||||
use crate::FloatOrInt;
|
||||
|
||||
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::from_array_unpremul([0.25, 0.25, 0.25, 1.]);
|
||||
@@ -222,23 +222,15 @@ impl CornerRadius {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(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 width: f64,
|
||||
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>,
|
||||
}
|
||||
|
||||
@@ -246,7 +238,7 @@ impl Default for FocusRing {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
off: false,
|
||||
width: FloatOrInt(4.),
|
||||
width: 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),
|
||||
@@ -257,23 +249,15 @@ impl Default for FocusRing {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(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 width: f64,
|
||||
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>,
|
||||
}
|
||||
|
||||
@@ -281,7 +265,7 @@ impl Default for Border {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
off: true,
|
||||
width: FloatOrInt(4.),
|
||||
width: 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),
|
||||
@@ -329,7 +313,7 @@ impl MergeWith<BorderRule> for Border {
|
||||
self.off = false;
|
||||
}
|
||||
|
||||
merge_clone!((self, part), width);
|
||||
merge!((self, part), width);
|
||||
|
||||
merge_color_gradient!(
|
||||
(self, part),
|
||||
@@ -348,21 +332,14 @@ impl MergeWith<BorderRule> for FocusRing {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(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 softness: f64,
|
||||
pub spread: f64,
|
||||
pub draw_behind_window: bool,
|
||||
#[knuffel(child, default = Self::default().color)]
|
||||
pub color: Color,
|
||||
#[knuffel(child)]
|
||||
pub inactive_color: Option<Color>,
|
||||
}
|
||||
|
||||
@@ -374,8 +351,8 @@ impl Default for Shadow {
|
||||
x: FloatOrInt(0.),
|
||||
y: FloatOrInt(5.),
|
||||
},
|
||||
softness: FloatOrInt(30.),
|
||||
spread: FloatOrInt(5.),
|
||||
softness: 30.,
|
||||
spread: 5.,
|
||||
draw_behind_window: false,
|
||||
color: Color::from_rgba8_unpremul(0, 0, 0, 0x77),
|
||||
inactive_color: None,
|
||||
@@ -390,7 +367,7 @@ impl MergeWith<ShadowRule> for Shadow {
|
||||
self.on = false;
|
||||
}
|
||||
|
||||
merge_clone!((self, part), softness, spread);
|
||||
merge!((self, part), softness, spread);
|
||||
|
||||
merge_clone!((self, part), offset, draw_behind_window, color);
|
||||
|
||||
@@ -440,8 +417,8 @@ impl From<WorkspaceShadow> for Shadow {
|
||||
Self {
|
||||
on: !value.off,
|
||||
offset: value.offset,
|
||||
softness: value.softness,
|
||||
spread: value.spread,
|
||||
softness: value.softness.0,
|
||||
spread: value.spread.0,
|
||||
draw_behind_window: false,
|
||||
color: value.color,
|
||||
inactive_color: None,
|
||||
@@ -449,26 +426,99 @@ impl From<WorkspaceShadow> for Shadow {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct TabIndicator {
|
||||
pub off: bool,
|
||||
pub hide_when_single_tab: bool,
|
||||
pub place_within_column: bool,
|
||||
pub gap: f64,
|
||||
pub width: f64,
|
||||
pub length: TabIndicatorLength,
|
||||
pub position: TabIndicatorPosition,
|
||||
pub gaps_between_tabs: f64,
|
||||
pub corner_radius: f64,
|
||||
pub active_color: Option<Color>,
|
||||
pub inactive_color: Option<Color>,
|
||||
pub urgent_color: Option<Color>,
|
||||
pub active_gradient: Option<Gradient>,
|
||||
pub inactive_gradient: Option<Gradient>,
|
||||
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: 5.,
|
||||
width: 4.,
|
||||
length: TabIndicatorLength {
|
||||
total_proportion: Some(0.5),
|
||||
},
|
||||
position: TabIndicatorPosition::Left,
|
||||
gaps_between_tabs: 0.,
|
||||
corner_radius: 0.,
|
||||
active_color: None,
|
||||
inactive_color: None,
|
||||
urgent_color: None,
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeWith<TabIndicatorPart> for TabIndicator {
|
||||
fn merge_with(&mut self, part: &TabIndicatorPart) {
|
||||
self.off |= part.off;
|
||||
if part.on {
|
||||
self.off = false;
|
||||
}
|
||||
|
||||
merge!(
|
||||
(self, part),
|
||||
hide_when_single_tab,
|
||||
place_within_column,
|
||||
gap,
|
||||
width,
|
||||
gaps_between_tabs,
|
||||
corner_radius,
|
||||
);
|
||||
|
||||
merge_clone!((self, part), length, position);
|
||||
|
||||
merge_color_gradient_opt!(
|
||||
(self, part),
|
||||
(active_color, active_gradient),
|
||||
(inactive_color, inactive_gradient),
|
||||
(urgent_color, urgent_gradient),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
|
||||
pub struct TabIndicatorPart {
|
||||
#[knuffel(child)]
|
||||
pub off: bool,
|
||||
#[knuffel(child)]
|
||||
pub hide_when_single_tab: bool,
|
||||
pub on: 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>,
|
||||
pub hide_when_single_tab: Option<Flag>,
|
||||
#[knuffel(child)]
|
||||
pub place_within_column: Option<Flag>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub gap: Option<FloatOrInt<-65535, 65535>>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub width: Option<FloatOrInt<0, 65535>>,
|
||||
#[knuffel(child)]
|
||||
pub length: Option<TabIndicatorLength>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub position: Option<TabIndicatorPosition>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub gaps_between_tabs: Option<FloatOrInt<0, 65535>>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub corner_radius: Option<FloatOrInt<0, 65535>>,
|
||||
#[knuffel(child)]
|
||||
pub active_color: Option<Color>,
|
||||
#[knuffel(child)]
|
||||
@@ -483,30 +533,6 @@ pub struct TabIndicator {
|
||||
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)]
|
||||
@@ -521,13 +547,10 @@ pub enum TabIndicatorPosition {
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(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>,
|
||||
}
|
||||
|
||||
@@ -541,6 +564,29 @@ impl Default for InsertHint {
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeWith<InsertHintPart> for InsertHint {
|
||||
fn merge_with(&mut self, part: &InsertHintPart) {
|
||||
self.off |= part.off;
|
||||
if part.on {
|
||||
self.off = false;
|
||||
}
|
||||
|
||||
merge_color_gradient!((self, part), (color, gradient));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
|
||||
pub struct InsertHintPart {
|
||||
#[knuffel(child)]
|
||||
pub off: bool,
|
||||
#[knuffel(child)]
|
||||
pub on: bool,
|
||||
#[knuffel(child)]
|
||||
pub color: Option<Color>,
|
||||
#[knuffel(child)]
|
||||
pub gradient: Option<Gradient>,
|
||||
}
|
||||
|
||||
#[derive(knuffel::DecodeScalar, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BlockOutFrom {
|
||||
Screencast,
|
||||
@@ -1016,16 +1062,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_border_rule_on_off_merging() {
|
||||
fn is_on(config: &str, rules: &[&str]) -> String {
|
||||
let mut resolved = BorderRule {
|
||||
off: false,
|
||||
on: false,
|
||||
width: None,
|
||||
active_color: None,
|
||||
inactive_color: None,
|
||||
urgent_color: None,
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
let mut resolved = Border {
|
||||
off: config == "off",
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
for rule in rules.iter().copied() {
|
||||
@@ -1038,14 +1077,7 @@ mod tests {
|
||||
resolved.merge_with(&rule);
|
||||
}
|
||||
|
||||
let mut border = Border {
|
||||
off: config == "off",
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
border.merge_with(&resolved);
|
||||
|
||||
if border.off { "off" } else { "on" }.to_owned()
|
||||
if resolved.off { "off" } else { "on" }.to_owned()
|
||||
}
|
||||
|
||||
assert_snapshot!(is_on("off", &[]), @"off");
|
||||
@@ -1095,13 +1127,11 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut border_rule = BorderRule::default();
|
||||
let mut border = config.resolve_layout().border;
|
||||
for rule in &config.window_rules {
|
||||
border_rule.merge_with(&rule.border);
|
||||
border.merge_with(&rule.border);
|
||||
}
|
||||
|
||||
let border = config.layout.border.merged_with(&border_rule);
|
||||
|
||||
// Gradient should be None because it's overwritten.
|
||||
assert_debug_snapshot!(
|
||||
(
|
||||
@@ -1166,15 +1196,13 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut border_rule = BorderRule::default();
|
||||
let mut border = config.resolve_layout().border;
|
||||
let mut tab_indicator_rule = TabIndicatorRule::default();
|
||||
for rule in &config.window_rules {
|
||||
border_rule.merge_with(&rule.border);
|
||||
border.merge_with(&rule.border);
|
||||
tab_indicator_rule.merge_with(&rule.tab_indicator);
|
||||
}
|
||||
|
||||
let border = config.layout.border.merged_with(&border_rule);
|
||||
|
||||
// Gradient should be None because it's overwritten.
|
||||
assert_debug_snapshot!(
|
||||
(
|
||||
|
@@ -4,65 +4,130 @@ use niri_ipc::{ColumnDisplay, SizeChange};
|
||||
use crate::appearance::{
|
||||
Border, FocusRing, InsertHint, Shadow, TabIndicator, DEFAULT_BACKGROUND_COLOR,
|
||||
};
|
||||
use crate::utils::expect_only_children;
|
||||
use crate::{Color, FloatOrInt};
|
||||
use crate::utils::{expect_only_children, Flag, MergeWith};
|
||||
use crate::{BorderRule, Color, FloatOrInt, InsertHintPart, ShadowRule, TabIndicatorPart};
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
|
||||
#[derive(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 default_column_width: Option<PresetSize>,
|
||||
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 gaps: f64,
|
||||
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(),
|
||||
focus_ring: FocusRing::default(),
|
||||
border: Border::default(),
|
||||
shadow: Shadow::default(),
|
||||
tab_indicator: TabIndicator::default(),
|
||||
insert_hint: InsertHint::default(),
|
||||
preset_column_widths: vec![
|
||||
PresetSize::Proportion(1. / 3.),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Proportion(2. / 3.),
|
||||
],
|
||||
default_column_width: Some(PresetSize::Proportion(0.5)),
|
||||
center_focused_column: CenterFocusedColumn::Never,
|
||||
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(),
|
||||
gaps: 16.,
|
||||
struts: Struts::default(),
|
||||
preset_window_heights: vec![
|
||||
PresetSize::Proportion(1. / 3.),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Proportion(2. / 3.),
|
||||
],
|
||||
background_color: DEFAULT_BACKGROUND_COLOR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeWith<LayoutPart> for Layout {
|
||||
fn merge_with(&mut self, part: &LayoutPart) {
|
||||
merge!(
|
||||
(self, part),
|
||||
focus_ring,
|
||||
border,
|
||||
shadow,
|
||||
tab_indicator,
|
||||
insert_hint,
|
||||
always_center_single_column,
|
||||
empty_workspace_above_first,
|
||||
gaps,
|
||||
);
|
||||
|
||||
merge_clone!(
|
||||
(self, part),
|
||||
preset_column_widths,
|
||||
preset_window_heights,
|
||||
center_focused_column,
|
||||
default_column_display,
|
||||
struts,
|
||||
background_color,
|
||||
);
|
||||
|
||||
if let Some(x) = part.default_column_width {
|
||||
self.default_column_width = x.0;
|
||||
}
|
||||
|
||||
if self.preset_column_widths.is_empty() {
|
||||
self.preset_column_widths = Layout::default().preset_column_widths;
|
||||
}
|
||||
|
||||
if self.preset_window_heights.is_empty() {
|
||||
self.preset_window_heights = Layout::default().preset_window_heights;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Default, Clone, PartialEq)]
|
||||
pub struct LayoutPart {
|
||||
#[knuffel(child)]
|
||||
pub focus_ring: Option<BorderRule>,
|
||||
#[knuffel(child)]
|
||||
pub border: Option<BorderRule>,
|
||||
#[knuffel(child)]
|
||||
pub shadow: Option<ShadowRule>,
|
||||
#[knuffel(child)]
|
||||
pub tab_indicator: Option<TabIndicatorPart>,
|
||||
#[knuffel(child)]
|
||||
pub insert_hint: Option<InsertHintPart>,
|
||||
#[knuffel(child, unwrap(children))]
|
||||
pub preset_column_widths: Option<Vec<PresetSize>>,
|
||||
#[knuffel(child)]
|
||||
pub default_column_width: Option<DefaultPresetSize>,
|
||||
#[knuffel(child, unwrap(children))]
|
||||
pub preset_window_heights: Option<Vec<PresetSize>>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub center_focused_column: Option<CenterFocusedColumn>,
|
||||
#[knuffel(child)]
|
||||
pub always_center_single_column: Option<Flag>,
|
||||
#[knuffel(child)]
|
||||
pub empty_workspace_above_first: Option<Flag>,
|
||||
#[knuffel(child, unwrap(argument, str))]
|
||||
pub default_column_display: Option<ColumnDisplay>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub gaps: Option<FloatOrInt<0, 65535>>,
|
||||
#[knuffel(child)]
|
||||
pub struts: Option<Struts>,
|
||||
#[knuffel(child)]
|
||||
pub background_color: Option<Color>,
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum PresetSize {
|
||||
Proportion(#[knuffel(argument)] f64),
|
||||
|
@@ -36,6 +36,7 @@ pub use crate::layout::*;
|
||||
pub use crate::misc::*;
|
||||
pub use crate::output::{Output, OutputName, Outputs, Position, Vrr};
|
||||
pub use crate::utils::FloatOrInt;
|
||||
use crate::utils::MergeWith as _;
|
||||
pub use crate::window_rule::{FloatingPosition, RelativeTo, WindowRule};
|
||||
pub use crate::workspace::Workspace;
|
||||
|
||||
@@ -50,7 +51,7 @@ pub struct Config {
|
||||
#[knuffel(children(name = "spawn-sh-at-startup"))]
|
||||
pub spawn_sh_at_startup: Vec<SpawnShAtStartup>,
|
||||
#[knuffel(child, default)]
|
||||
pub layout: Layout,
|
||||
pub layout: LayoutPart,
|
||||
#[knuffel(child, default)]
|
||||
pub prefer_no_csd: bool,
|
||||
#[knuffel(child, default)]
|
||||
@@ -133,6 +134,35 @@ impl Config {
|
||||
let _span = tracy_client::span!("Config::parse");
|
||||
knuffel::parse(filename, text)
|
||||
}
|
||||
|
||||
pub fn resolve_layout(&self) -> Layout {
|
||||
let mut rv = Layout::from_part(&self.layout);
|
||||
|
||||
// Preserve the behavior we'd always had for the border section:
|
||||
// - `layout {}` gives border = off
|
||||
// - `layout { border {} }` gives border = on
|
||||
// - `layout { border { off } }` gives border = off
|
||||
//
|
||||
// This behavior is inconsistent with the rest of the config where adding an empty section
|
||||
// generally doesn't change the outcome. Particularly, shadows are also disabled by default
|
||||
// (like borders), and they always had an `on` instead of an `off` for this reason, so that
|
||||
// writing `layout { shadow {} }` still results in shadow = off, as it should.
|
||||
//
|
||||
// Unfortunately, the default config has always had wording that heavily implies that
|
||||
// `layout { border {} }` enables the borders. This wording is sure to be present in a lot
|
||||
// of users' configs by now, which we can't change.
|
||||
//
|
||||
// Another way to make things consistent would be to default borders to on. However, that
|
||||
// is annoying because it would mean changing many tests that rely on borders being off by
|
||||
// default. This would also contradict the intended default borders value (off).
|
||||
//
|
||||
// So, let's just work around the problem here, preserving the original behavior.
|
||||
if self.layout.border.is_some_and(|x| !x.on && !x.off) {
|
||||
rv.border.off = false;
|
||||
}
|
||||
|
||||
rv
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -778,181 +808,182 @@ mod tests {
|
||||
command: "qs -c ~/source/qs/MyAwesomeShell",
|
||||
},
|
||||
],
|
||||
layout: Layout {
|
||||
focus_ring: FocusRing {
|
||||
off: false,
|
||||
width: FloatOrInt(
|
||||
5.0,
|
||||
),
|
||||
active_color: Color {
|
||||
r: 0.0,
|
||||
g: 0.39215687,
|
||||
b: 0.78431374,
|
||||
a: 1.0,
|
||||
},
|
||||
inactive_color: Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.39215687,
|
||||
a: 0.0,
|
||||
},
|
||||
urgent_color: Color {
|
||||
r: 0.60784316,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
},
|
||||
active_gradient: Some(
|
||||
Gradient {
|
||||
from: Color {
|
||||
r: 0.039215688,
|
||||
g: 0.078431375,
|
||||
b: 0.11764706,
|
||||
a: 1.0,
|
||||
},
|
||||
to: Color {
|
||||
layout: LayoutPart {
|
||||
focus_ring: Some(
|
||||
BorderRule {
|
||||
off: false,
|
||||
on: false,
|
||||
width: Some(
|
||||
FloatOrInt(
|
||||
5.0,
|
||||
),
|
||||
),
|
||||
active_color: Some(
|
||||
Color {
|
||||
r: 0.0,
|
||||
g: 0.5019608,
|
||||
b: 1.0,
|
||||
g: 0.39215687,
|
||||
b: 0.78431374,
|
||||
a: 1.0,
|
||||
},
|
||||
angle: 180,
|
||||
relative_to: WorkspaceView,
|
||||
in_: GradientInterpolation {
|
||||
color_space: Srgb,
|
||||
hue_interpolation: Shorter,
|
||||
),
|
||||
inactive_color: Some(
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.39215687,
|
||||
a: 0.0,
|
||||
},
|
||||
},
|
||||
),
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
border: Border {
|
||||
off: false,
|
||||
width: FloatOrInt(
|
||||
3.0,
|
||||
),
|
||||
active_color: Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.49803922,
|
||||
a: 1.0,
|
||||
},
|
||||
inactive_color: Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.39215687,
|
||||
a: 0.0,
|
||||
},
|
||||
urgent_color: Color {
|
||||
r: 0.60784316,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
},
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
shadow: Shadow {
|
||||
on: false,
|
||||
offset: ShadowOffset {
|
||||
x: FloatOrInt(
|
||||
10.0,
|
||||
),
|
||||
y: FloatOrInt(
|
||||
-20.0,
|
||||
urgent_color: None,
|
||||
active_gradient: Some(
|
||||
Gradient {
|
||||
from: Color {
|
||||
r: 0.039215688,
|
||||
g: 0.078431375,
|
||||
b: 0.11764706,
|
||||
a: 1.0,
|
||||
},
|
||||
to: Color {
|
||||
r: 0.0,
|
||||
g: 0.5019608,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
},
|
||||
angle: 180,
|
||||
relative_to: WorkspaceView,
|
||||
in_: GradientInterpolation {
|
||||
color_space: Srgb,
|
||||
hue_interpolation: Shorter,
|
||||
},
|
||||
},
|
||||
),
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
),
|
||||
border: Some(
|
||||
BorderRule {
|
||||
off: false,
|
||||
on: false,
|
||||
width: Some(
|
||||
FloatOrInt(
|
||||
3.0,
|
||||
),
|
||||
),
|
||||
active_color: None,
|
||||
inactive_color: Some(
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.39215687,
|
||||
a: 0.0,
|
||||
},
|
||||
),
|
||||
urgent_color: None,
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
),
|
||||
shadow: Some(
|
||||
ShadowRule {
|
||||
off: false,
|
||||
on: false,
|
||||
offset: Some(
|
||||
ShadowOffset {
|
||||
x: FloatOrInt(
|
||||
10.0,
|
||||
),
|
||||
y: FloatOrInt(
|
||||
-20.0,
|
||||
),
|
||||
},
|
||||
),
|
||||
softness: None,
|
||||
spread: None,
|
||||
draw_behind_window: None,
|
||||
color: None,
|
||||
inactive_color: None,
|
||||
},
|
||||
),
|
||||
tab_indicator: Some(
|
||||
TabIndicatorPart {
|
||||
off: false,
|
||||
on: false,
|
||||
hide_when_single_tab: None,
|
||||
place_within_column: None,
|
||||
gap: None,
|
||||
width: Some(
|
||||
FloatOrInt(
|
||||
10.0,
|
||||
),
|
||||
),
|
||||
length: None,
|
||||
position: Some(
|
||||
Top,
|
||||
),
|
||||
gaps_between_tabs: None,
|
||||
corner_radius: None,
|
||||
active_color: None,
|
||||
inactive_color: None,
|
||||
urgent_color: None,
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
),
|
||||
insert_hint: Some(
|
||||
InsertHintPart {
|
||||
off: false,
|
||||
on: false,
|
||||
color: Some(
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.49803922,
|
||||
a: 1.0,
|
||||
},
|
||||
),
|
||||
gradient: Some(
|
||||
Gradient {
|
||||
from: Color {
|
||||
r: 0.039215688,
|
||||
g: 0.078431375,
|
||||
b: 0.11764706,
|
||||
a: 1.0,
|
||||
},
|
||||
to: Color {
|
||||
r: 0.0,
|
||||
g: 0.5019608,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
},
|
||||
angle: 180,
|
||||
relative_to: WorkspaceView,
|
||||
in_: GradientInterpolation {
|
||||
color_space: Srgb,
|
||||
hue_interpolation: Shorter,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
softness: FloatOrInt(
|
||||
30.0,
|
||||
),
|
||||
spread: FloatOrInt(
|
||||
5.0,
|
||||
),
|
||||
draw_behind_window: false,
|
||||
color: Color {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 0.46666667,
|
||||
},
|
||||
inactive_color: None,
|
||||
},
|
||||
tab_indicator: TabIndicator {
|
||||
off: false,
|
||||
hide_when_single_tab: false,
|
||||
place_within_column: false,
|
||||
gap: FloatOrInt(
|
||||
5.0,
|
||||
),
|
||||
width: FloatOrInt(
|
||||
10.0,
|
||||
),
|
||||
length: TabIndicatorLength {
|
||||
total_proportion: Some(
|
||||
),
|
||||
preset_column_widths: Some(
|
||||
[
|
||||
Proportion(
|
||||
0.25,
|
||||
),
|
||||
Proportion(
|
||||
0.5,
|
||||
),
|
||||
},
|
||||
position: Top,
|
||||
gaps_between_tabs: FloatOrInt(
|
||||
0.0,
|
||||
),
|
||||
corner_radius: FloatOrInt(
|
||||
0.0,
|
||||
),
|
||||
active_color: None,
|
||||
inactive_color: None,
|
||||
urgent_color: None,
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
insert_hint: InsertHint {
|
||||
off: false,
|
||||
color: Color {
|
||||
r: 1.0,
|
||||
g: 0.78431374,
|
||||
b: 0.49803922,
|
||||
a: 1.0,
|
||||
},
|
||||
gradient: Some(
|
||||
Gradient {
|
||||
from: Color {
|
||||
r: 0.039215688,
|
||||
g: 0.078431375,
|
||||
b: 0.11764706,
|
||||
a: 1.0,
|
||||
},
|
||||
to: Color {
|
||||
r: 0.0,
|
||||
g: 0.5019608,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
},
|
||||
angle: 180,
|
||||
relative_to: WorkspaceView,
|
||||
in_: GradientInterpolation {
|
||||
color_space: Srgb,
|
||||
hue_interpolation: Shorter,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
preset_column_widths: [
|
||||
Proportion(
|
||||
0.25,
|
||||
),
|
||||
Proportion(
|
||||
0.5,
|
||||
),
|
||||
Fixed(
|
||||
960,
|
||||
),
|
||||
Fixed(
|
||||
1280,
|
||||
),
|
||||
],
|
||||
Fixed(
|
||||
960,
|
||||
),
|
||||
Fixed(
|
||||
1280,
|
||||
),
|
||||
],
|
||||
),
|
||||
default_column_width: Some(
|
||||
DefaultPresetSize(
|
||||
Some(
|
||||
@@ -962,47 +993,52 @@ mod tests {
|
||||
),
|
||||
),
|
||||
),
|
||||
preset_window_heights: [
|
||||
Proportion(
|
||||
0.25,
|
||||
),
|
||||
Proportion(
|
||||
0.5,
|
||||
),
|
||||
Fixed(
|
||||
960,
|
||||
),
|
||||
Fixed(
|
||||
1280,
|
||||
),
|
||||
],
|
||||
center_focused_column: OnOverflow,
|
||||
always_center_single_column: false,
|
||||
empty_workspace_above_first: false,
|
||||
default_column_display: Tabbed,
|
||||
gaps: FloatOrInt(
|
||||
8.0,
|
||||
preset_window_heights: Some(
|
||||
[
|
||||
Proportion(
|
||||
0.25,
|
||||
),
|
||||
Proportion(
|
||||
0.5,
|
||||
),
|
||||
Fixed(
|
||||
960,
|
||||
),
|
||||
Fixed(
|
||||
1280,
|
||||
),
|
||||
],
|
||||
),
|
||||
struts: Struts {
|
||||
left: FloatOrInt(
|
||||
1.0,
|
||||
center_focused_column: Some(
|
||||
OnOverflow,
|
||||
),
|
||||
always_center_single_column: None,
|
||||
empty_workspace_above_first: None,
|
||||
default_column_display: Some(
|
||||
Tabbed,
|
||||
),
|
||||
gaps: Some(
|
||||
FloatOrInt(
|
||||
8.0,
|
||||
),
|
||||
right: FloatOrInt(
|
||||
2.0,
|
||||
),
|
||||
top: FloatOrInt(
|
||||
3.0,
|
||||
),
|
||||
bottom: FloatOrInt(
|
||||
0.0,
|
||||
),
|
||||
},
|
||||
background_color: Color {
|
||||
r: 0.25,
|
||||
g: 0.25,
|
||||
b: 0.25,
|
||||
a: 1.0,
|
||||
},
|
||||
),
|
||||
struts: Some(
|
||||
Struts {
|
||||
left: FloatOrInt(
|
||||
1.0,
|
||||
),
|
||||
right: FloatOrInt(
|
||||
2.0,
|
||||
),
|
||||
top: FloatOrInt(
|
||||
3.0,
|
||||
),
|
||||
bottom: FloatOrInt(
|
||||
0.0,
|
||||
),
|
||||
},
|
||||
),
|
||||
background_color: None,
|
||||
},
|
||||
prefer_no_csd: true,
|
||||
cursor: Cursor {
|
||||
@@ -1823,6 +1859,23 @@ mod tests {
|
||||
default_config.window_rules.clear();
|
||||
default_config.binds.0.clear();
|
||||
|
||||
let default_layout = default_config.resolve_layout();
|
||||
let empty_layout = empty_config.resolve_layout();
|
||||
default_config.layout = Default::default();
|
||||
assert_snapshot!(
|
||||
diff_lines(
|
||||
&format!("{empty_layout:#?}"),
|
||||
&format!("{default_layout:#?}")
|
||||
),
|
||||
@r"
|
||||
- 0.3333333333333333,
|
||||
+ 0.33333,
|
||||
|
||||
- 0.6666666666666666,
|
||||
+ 0.66667,
|
||||
",
|
||||
);
|
||||
|
||||
assert_snapshot!(
|
||||
diff_lines(
|
||||
&format!("{empty_config:#?}"),
|
||||
@@ -1846,30 +1899,7 @@ mod tests {
|
||||
+ ],
|
||||
+ },
|
||||
+ ],
|
||||
|
||||
- preset_column_widths: [],
|
||||
- default_column_width: None,
|
||||
+ preset_column_widths: [
|
||||
+ Proportion(
|
||||
+ 0.33333,
|
||||
+ ),
|
||||
+ Proportion(
|
||||
+ 0.5,
|
||||
+ ),
|
||||
+ Proportion(
|
||||
+ 0.66667,
|
||||
+ ),
|
||||
+ ],
|
||||
+ default_column_width: Some(
|
||||
+ DefaultPresetSize(
|
||||
+ Some(
|
||||
+ Proportion(
|
||||
+ 0.5,
|
||||
+ ),
|
||||
+ ),
|
||||
+ ),
|
||||
+ ),
|
||||
"#
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,13 @@
|
||||
macro_rules! merge {
|
||||
(($self:expr, $part:expr), $($field:ident),+ $(,)*) => {
|
||||
$(
|
||||
if let Some(x) = &$part.$field {
|
||||
$self.$field.merge_with(x);
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! merge_clone {
|
||||
(($self:expr, $part:expr), $($field:ident),+ $(,)*) => {
|
||||
$(
|
||||
|
@@ -14,6 +14,15 @@ pub struct Percent(pub f64);
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
||||
pub struct FloatOrInt<const MIN: i32, const MAX: i32>(pub f64);
|
||||
|
||||
/// Flag, with an optional explicit value.
|
||||
///
|
||||
/// Intended to be used as an `Option<MaybeBool>` field, as a tri-state:
|
||||
/// - (missing): unset, `None`
|
||||
/// - just `field`: set, `Some(true)`
|
||||
/// - explicitly `field true` or `field false`: set, `Some(true)` or `Some(false)`
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Flag(#[knuffel(argument, default = true)] pub bool);
|
||||
|
||||
/// `Regex` that implements `PartialEq` by its string form.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RegexEq(pub Regex);
|
||||
@@ -57,6 +66,12 @@ impl<const MIN: i32, const MAX: i32> MergeWith<FloatOrInt<MIN, MAX>> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeWith<Flag> for bool {
|
||||
fn merge_with(&mut self, part: &Flag) {
|
||||
*self = part.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: knuffel::traits::ErrorSpan, const MIN: i32, const MAX: i32> knuffel::DecodeScalar<S>
|
||||
for FloatOrInt<MIN, MAX>
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@ use std::time::Duration;
|
||||
|
||||
use niri::layout::focus_ring::FocusRing;
|
||||
use niri::render_helpers::border::BorderRenderElement;
|
||||
use niri_config::{Color, CornerRadius, FloatOrInt, GradientInterpolation};
|
||||
use niri_config::{Color, CornerRadius, GradientInterpolation};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Physical, Point, Rectangle, Size};
|
||||
@@ -20,7 +20,7 @@ impl GradientArea {
|
||||
pub fn new(_args: Args) -> Self {
|
||||
let border = FocusRing::new(niri_config::FocusRing {
|
||||
off: false,
|
||||
width: FloatOrInt(1.),
|
||||
width: 1.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 255, 255, 128),
|
||||
inactive_color: Color::default(),
|
||||
urgent_color: Color::default(),
|
||||
|
@@ -4,7 +4,7 @@ use std::time::Duration;
|
||||
use niri::animation::Clock;
|
||||
use niri::layout::{ActivateWindow, AddWindowTarget, LayoutElement as _, Options};
|
||||
use niri::render_helpers::RenderTarget;
|
||||
use niri_config::{Color, FloatOrInt, OutputName, PresetSize};
|
||||
use niri_config::{Color, OutputName, PresetSize};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::desktop::layer_map_for_output;
|
||||
@@ -58,7 +58,7 @@ impl Layout {
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: FloatOrInt(4.),
|
||||
width: 4.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255),
|
||||
urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
|
||||
|
@@ -3,7 +3,7 @@ use std::time::Duration;
|
||||
|
||||
use niri::layout::Options;
|
||||
use niri::render_helpers::RenderTarget;
|
||||
use niri_config::{Color, FloatOrInt};
|
||||
use niri_config::Color;
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::utils::{Physical, Point, Rectangle, Size};
|
||||
@@ -64,7 +64,7 @@ impl Tile {
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: FloatOrInt(32.),
|
||||
width: 32.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
..Default::default()
|
||||
},
|
||||
|
@@ -59,7 +59,7 @@ impl MappedLayer {
|
||||
clock: Clock,
|
||||
config: &Config,
|
||||
) -> Self {
|
||||
let mut shadow_config = config.layout.shadow;
|
||||
let mut shadow_config = config.resolve_layout().shadow;
|
||||
// Shadows for layer surfaces need to be explicitly enabled.
|
||||
shadow_config.on = false;
|
||||
shadow_config.merge_with(&rules.shadow);
|
||||
@@ -76,7 +76,7 @@ impl MappedLayer {
|
||||
}
|
||||
|
||||
pub fn update_config(&mut self, config: &Config) {
|
||||
let mut shadow_config = config.layout.shadow;
|
||||
let mut shadow_config = config.resolve_layout().shadow;
|
||||
// Shadows for layer surfaces need to be explicitly enabled.
|
||||
shadow_config.on = false;
|
||||
shadow_config.merge_with(&self.rules.shadow);
|
||||
|
@@ -1227,7 +1227,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
let size = match resolve_preset_size(size, working_area_size) {
|
||||
ResolvedSize::Tile(mut size) => {
|
||||
if !border.off {
|
||||
size -= border.width.0 * 2.;
|
||||
size -= border.width * 2.;
|
||||
}
|
||||
size
|
||||
}
|
||||
@@ -1365,7 +1365,7 @@ fn compute_toplevel_bounds(
|
||||
) -> Size<i32, Logical> {
|
||||
let mut border = 0.;
|
||||
if !border_config.off {
|
||||
border = border_config.width.0 * 2.;
|
||||
border = border_config.width * 2.;
|
||||
}
|
||||
|
||||
Size::from((
|
||||
|
@@ -65,7 +65,7 @@ impl FocusRing {
|
||||
scale: f64,
|
||||
alpha: f32,
|
||||
) {
|
||||
let width = self.config.width.0;
|
||||
let width = self.config.width;
|
||||
self.full_size = win_size + Size::from((width, width)).upscale(2.);
|
||||
|
||||
let color = if is_urgent {
|
||||
@@ -261,7 +261,7 @@ impl FocusRing {
|
||||
}
|
||||
|
||||
pub fn width(&self) -> f64 {
|
||||
self.config.width.0
|
||||
self.config.width
|
||||
}
|
||||
|
||||
pub fn is_off(&self) -> bool {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
use niri_config::{CornerRadius, FloatOrInt};
|
||||
use niri_config::CornerRadius;
|
||||
use smithay::utils::{Logical, Point, Rectangle, Size};
|
||||
|
||||
use super::focus_ring::{FocusRing, FocusRingRenderElement};
|
||||
@@ -16,7 +16,7 @@ impl InsertHintElement {
|
||||
Self {
|
||||
inner: FocusRing::new(niri_config::FocusRing {
|
||||
off: config.off,
|
||||
width: FloatOrInt(0.),
|
||||
width: 0.,
|
||||
active_color: config.color,
|
||||
inactive_color: config.color,
|
||||
urgent_color: config.color,
|
||||
@@ -30,7 +30,7 @@ impl InsertHintElement {
|
||||
pub fn update_config(&mut self, config: niri_config::InsertHint) {
|
||||
self.inner.update_config(niri_config::FocusRing {
|
||||
off: config.off,
|
||||
width: FloatOrInt(0.),
|
||||
width: 0.,
|
||||
active_color: config.color,
|
||||
inactive_color: config.color,
|
||||
urgent_color: config.color,
|
||||
|
@@ -40,8 +40,8 @@ use std::time::Duration;
|
||||
use monitor::{InsertHint, InsertPosition, InsertWorkspace, MonitorAddWindowTarget};
|
||||
use niri_config::utils::MergeWith as _;
|
||||
use niri_config::{
|
||||
CenterFocusedColumn, Config, CornerRadius, FloatOrInt, PresetSize, Struts,
|
||||
Workspace as WorkspaceConfig, WorkspaceReference,
|
||||
CenterFocusedColumn, Config, CornerRadius, PresetSize, Struts, Workspace as WorkspaceConfig,
|
||||
WorkspaceReference,
|
||||
};
|
||||
use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
|
||||
use scrolling::{Column, ColumnWidth};
|
||||
@@ -620,7 +620,7 @@ impl HitType {
|
||||
|
||||
impl Options {
|
||||
fn from_config(config: &Config) -> Self {
|
||||
let layout = &config.layout;
|
||||
let layout = config.resolve_layout();
|
||||
|
||||
let preset_column_widths = if layout.preset_column_widths.is_empty() {
|
||||
Options::default().preset_column_widths
|
||||
@@ -633,16 +633,8 @@ impl Options {
|
||||
layout.preset_window_heights.clone()
|
||||
};
|
||||
|
||||
// Missing default_column_width maps to Some(PresetSize::Proportion(0.5)),
|
||||
// while present, but empty, maps to None.
|
||||
let default_column_width = layout
|
||||
.default_column_width
|
||||
.as_ref()
|
||||
.map(|w| w.0)
|
||||
.unwrap_or(Some(PresetSize::Proportion(0.5)));
|
||||
|
||||
Self {
|
||||
gaps: layout.gaps.0,
|
||||
gaps: layout.gaps,
|
||||
struts: layout.struts,
|
||||
focus_ring: layout.focus_ring,
|
||||
border: layout.border,
|
||||
@@ -654,7 +646,7 @@ impl Options {
|
||||
empty_workspace_above_first: layout.empty_workspace_above_first,
|
||||
default_column_display: layout.default_column_display,
|
||||
preset_column_widths,
|
||||
default_column_width,
|
||||
default_column_width: layout.default_column_width,
|
||||
animations: config.animations.clone(),
|
||||
gestures: config.gestures,
|
||||
overview: config.overview,
|
||||
@@ -669,8 +661,8 @@ impl Options {
|
||||
let round = |logical: f64| round_logical_in_physical_max1(scale, logical);
|
||||
|
||||
self.gaps = round(self.gaps);
|
||||
self.focus_ring.width = FloatOrInt(round(self.focus_ring.width.0));
|
||||
self.border.width = FloatOrInt(round(self.border.width.0));
|
||||
self.focus_ring.width = round(self.focus_ring.width);
|
||||
self.border.width = round(self.border.width);
|
||||
|
||||
self
|
||||
}
|
||||
@@ -5252,7 +5244,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
let rules = window.rules();
|
||||
let border = self.options.border.merged_with(&rules.border);
|
||||
if !border.off {
|
||||
fixed += border.width.0 * 2.;
|
||||
fixed += border.width * 2.;
|
||||
}
|
||||
|
||||
ColumnWidth::Fixed(fixed)
|
||||
|
@@ -488,7 +488,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let size = match resolve_preset_size(size, &self.options, working_size.w, extra.w) {
|
||||
ResolvedSize::Tile(mut size) => {
|
||||
if !border.off {
|
||||
size -= border.width.0 * 2.;
|
||||
size -= border.width * 2.;
|
||||
}
|
||||
size
|
||||
}
|
||||
@@ -502,14 +502,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
let mut full_height = self.working_area.size.h - self.options.gaps * 2.;
|
||||
if !border.off {
|
||||
full_height -= border.width.0 * 2.;
|
||||
full_height -= border.width * 2.;
|
||||
}
|
||||
|
||||
let height = if let Some(height) = height {
|
||||
let height = match resolve_preset_size(height, &self.options, working_size.h, extra.h) {
|
||||
ResolvedSize::Tile(mut size) => {
|
||||
if !border.off {
|
||||
size -= border.width.0 * 2.;
|
||||
size -= border.width * 2.;
|
||||
}
|
||||
size
|
||||
}
|
||||
@@ -5280,7 +5280,7 @@ fn compute_toplevel_bounds(
|
||||
) -> Size<i32, Logical> {
|
||||
let mut border = 0.;
|
||||
if !border_config.off {
|
||||
border = border_config.width.0 * 2.;
|
||||
border = border_config.width * 2.;
|
||||
}
|
||||
|
||||
Size::from((
|
||||
|
@@ -48,7 +48,7 @@ impl Shadow {
|
||||
// * We do not divide anything, only add, subtract and multiply by integers.
|
||||
// * At rendering time, tile positions are rounded to physical pixels.
|
||||
|
||||
let width = self.config.softness.0;
|
||||
let width = self.config.softness;
|
||||
// Like in CSS box-shadow.
|
||||
let sigma = width / 2.;
|
||||
// Adjust width to draw all necessary pixels.
|
||||
@@ -57,7 +57,7 @@ impl Shadow {
|
||||
let offset = self.config.offset;
|
||||
let offset = Point::from((ceil(offset.x.0), ceil(offset.y.0)));
|
||||
|
||||
let spread = self.config.spread.0;
|
||||
let spread = self.config.spread;
|
||||
let spread = ceil(spread.abs()).copysign(spread);
|
||||
let offset = offset - Point::from((spread, spread));
|
||||
|
||||
|
@@ -83,10 +83,10 @@ impl TabIndicator {
|
||||
|
||||
let progress = self.open_anim.as_ref().map_or(1., |a| a.value().max(0.));
|
||||
|
||||
let width = round_max1(self.config.width.0);
|
||||
let gap = self.config.gap.0;
|
||||
let width = round_max1(self.config.width);
|
||||
let gap = self.config.gap;
|
||||
let gap = round_max1(gap.abs()).copysign(gap);
|
||||
let gaps_between = round_max1(self.config.gaps_between_tabs.0);
|
||||
let gaps_between = round_max1(self.config.gaps_between_tabs);
|
||||
|
||||
let position = self.config.position;
|
||||
let side = match position {
|
||||
@@ -104,7 +104,7 @@ impl TabIndicator {
|
||||
let px_per_tab = (length + gaps_between) / count as f64 - gaps_between;
|
||||
|
||||
let px_per_tab = px_per_tab * progress;
|
||||
let gaps_between = round(self.config.gaps_between_tabs.0 * progress);
|
||||
let gaps_between = round(self.config.gaps_between_tabs * progress);
|
||||
|
||||
let length = count as f64 * (px_per_tab + gaps_between) - gaps_between;
|
||||
let px_per_tab = floor_logical_in_physical_max1(scale, px_per_tab);
|
||||
@@ -185,8 +185,8 @@ impl TabIndicator {
|
||||
self.shader_locs.resize_with(count, Default::default);
|
||||
|
||||
let position = self.config.position;
|
||||
let radius = self.config.corner_radius.0 as f32;
|
||||
let shared_rounded_corners = self.config.gaps_between_tabs.0 == 0.;
|
||||
let radius = self.config.corner_radius as f32;
|
||||
let shared_rounded_corners = self.config.gaps_between_tabs == 0.;
|
||||
let mut tabs_left = tab_count;
|
||||
|
||||
let rects = self.tab_rects(area, count, scale);
|
||||
@@ -317,8 +317,8 @@ impl TabIndicator {
|
||||
}
|
||||
|
||||
let round = |logical: f64| round_logical_in_physical(scale, logical);
|
||||
let width = round(self.config.width.0);
|
||||
let gap = round(self.config.gap.0);
|
||||
let width = round(self.config.width);
|
||||
let gap = round(self.config.gap);
|
||||
|
||||
// No, I am *not* falling into the rabbit hole of "what if the tab indicator is wide enough
|
||||
// that it peeks from the other side of the window".
|
||||
|
@@ -2067,7 +2067,7 @@ fn large_negative_height_change() {
|
||||
|
||||
let mut options = Options::default();
|
||||
options.border.off = false;
|
||||
options.border.width = FloatOrInt(1.);
|
||||
options.border.width = 1.;
|
||||
|
||||
check_ops_with_options(options, ops);
|
||||
}
|
||||
@@ -2086,7 +2086,7 @@ fn large_max_size() {
|
||||
|
||||
let mut options = Options::default();
|
||||
options.border.off = false;
|
||||
options.border.width = FloatOrInt(1.);
|
||||
options.border.width = 1.;
|
||||
|
||||
check_ops_with_options(options, ops);
|
||||
}
|
||||
@@ -2292,8 +2292,9 @@ fn removing_all_outputs_preserves_empty_named_workspaces() {
|
||||
#[test]
|
||||
fn config_change_updates_cached_sizes() {
|
||||
let mut config = Config::default();
|
||||
config.layout.border.off = false;
|
||||
config.layout.border.width = FloatOrInt(2.);
|
||||
let border = config.layout.border.get_or_insert_with(Default::default);
|
||||
border.off = false;
|
||||
border.width = Some(FloatOrInt(2.));
|
||||
|
||||
let mut layout = Layout::new(Clock::default(), &config);
|
||||
|
||||
@@ -2305,7 +2306,11 @@ fn config_change_updates_cached_sizes() {
|
||||
}
|
||||
.apply(&mut layout);
|
||||
|
||||
config.layout.border.width = FloatOrInt(4.);
|
||||
config
|
||||
.layout
|
||||
.border
|
||||
.get_or_insert_with(Default::default)
|
||||
.width = Some(FloatOrInt(4.));
|
||||
layout.update_config(&config);
|
||||
|
||||
layout.verify_invariants();
|
||||
@@ -2314,7 +2319,7 @@ fn config_change_updates_cached_sizes() {
|
||||
#[test]
|
||||
fn preset_height_change_removes_preset() {
|
||||
let mut config = Config::default();
|
||||
config.layout.preset_window_heights = vec![PresetSize::Fixed(1), PresetSize::Fixed(2)];
|
||||
config.layout.preset_window_heights = Some(vec![PresetSize::Fixed(1), PresetSize::Fixed(2)]);
|
||||
|
||||
let mut layout = Layout::new(Clock::default(), &config);
|
||||
|
||||
@@ -2335,7 +2340,7 @@ fn preset_height_change_removes_preset() {
|
||||
}
|
||||
|
||||
// Leave only one.
|
||||
config.layout.preset_window_heights = vec![PresetSize::Fixed(1)];
|
||||
config.layout.preset_window_heights = Some(vec![PresetSize::Fixed(1)]);
|
||||
|
||||
layout.update_config(&config);
|
||||
|
||||
@@ -2424,7 +2429,7 @@ fn fixed_height_takes_max_non_auto_into_account() {
|
||||
let options = Options {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: niri_config::FloatOrInt(4.),
|
||||
width: 4.,
|
||||
..Default::default()
|
||||
},
|
||||
gaps: 0.,
|
||||
@@ -3173,7 +3178,7 @@ fn preset_column_width_fixed_correct_with_border() {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500)],
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: FloatOrInt(5.),
|
||||
width: 5.,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -3408,7 +3413,7 @@ prop_compose! {
|
||||
) -> niri_config::FocusRing {
|
||||
niri_config::FocusRing {
|
||||
off,
|
||||
width: FloatOrInt(width),
|
||||
width,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -3421,7 +3426,7 @@ prop_compose! {
|
||||
) -> niri_config::Border {
|
||||
niri_config::Border {
|
||||
off,
|
||||
width: FloatOrInt(width),
|
||||
width,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -3434,7 +3439,7 @@ prop_compose! {
|
||||
) -> niri_config::Shadow {
|
||||
niri_config::Shadow {
|
||||
on,
|
||||
softness: FloatOrInt(width),
|
||||
softness: width,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -3454,8 +3459,8 @@ prop_compose! {
|
||||
off,
|
||||
hide_when_single_tab,
|
||||
place_within_column,
|
||||
width: FloatOrInt(width),
|
||||
gap: FloatOrInt(gap),
|
||||
width,
|
||||
gap,
|
||||
length: TabIndicatorLength { total_proportion: Some(length) },
|
||||
position,
|
||||
..Default::default()
|
||||
|
@@ -190,7 +190,7 @@ fn unfullscreen_with_large_border() {
|
||||
let options = Options {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: niri_config::FloatOrInt(10000.),
|
||||
width: 10000.,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
@@ -1859,8 +1859,8 @@ fn compute_workspace_shadow_config(
|
||||
let norm = view_size.h / 1080.;
|
||||
|
||||
let mut config = niri_config::Shadow::from(config);
|
||||
config.softness.0 *= norm;
|
||||
config.spread.0 *= norm;
|
||||
config.softness *= norm;
|
||||
config.spread *= norm;
|
||||
config.offset.x.0 *= norm;
|
||||
config.offset.y.0 *= norm;
|
||||
|
||||
|
@@ -1657,7 +1657,7 @@ impl State {
|
||||
|
||||
let background_color = config
|
||||
.and_then(|c| c.background_color)
|
||||
.unwrap_or(full_config.layout.background_color)
|
||||
.unwrap_or_else(|| full_config.resolve_layout().background_color)
|
||||
.to_array_unpremul();
|
||||
let background_color = Color32F::from(background_color);
|
||||
|
||||
@@ -2906,7 +2906,7 @@ impl Niri {
|
||||
|
||||
let background_color = c
|
||||
.and_then(|c| c.background_color)
|
||||
.unwrap_or(config.layout.background_color)
|
||||
.unwrap_or_else(|| config.resolve_layout().background_color)
|
||||
.to_array_unpremul();
|
||||
|
||||
let mut backdrop_color = c
|
||||
|
@@ -74,7 +74,7 @@ fn set_up() -> Fixture {
|
||||
});
|
||||
|
||||
let mut config = Config::default();
|
||||
config.layout.gaps = FloatOrInt(0.0);
|
||||
config.layout.gaps = Some(FloatOrInt(0.0));
|
||||
config.animations.window_resize.anim.kind = LINEAR;
|
||||
config.animations.window_movement.0.kind = LINEAR;
|
||||
|
||||
|
Reference in New Issue
Block a user