Config window: every setting in config.toml, Hyprland options from Hyprland

All tunable values (sizes, timings, text sizes, colours, polls, equalizer
presets and bands, hotspot, extra output) are settings declared once in
config.rs, read from ~/.config/amane/config.toml, applied live on save.
shell.conf's four values move over on first start.

settings.rs: a normal window (control centre gear, or ipc config) with a
page per part, a page per Hyprland category, search and reset per row.
hypr.rs: Hyprland's options from hyprctl descriptions/getoption, applied
with hl.config and kept in ~/.config/hypr/amane.lua.
This commit is contained in:
server2
2026-10-15 02:18:57 +02:00
parent dfe3867529
commit 4fbfad3ce3
20 changed files with 3172 additions and 781 deletions
+31 -34
View File
@@ -8,18 +8,15 @@ use amane::{
Rectangle, Row, Service, Shadow, Stack, Start, Text, Vertical, Weight, Widget, Workspace, Workspaces, Zone,
};
use crate::edge::{self, Edge, HIDE_H, Part};
use crate::island::{CHIP_HOVER, CLEAR, COMPACT_H, HOVER_MS, SHADOW, TOP_GAP, backdrop, faded, mix};
use crate::config::appearance::{motion, overlays, text};
use crate::config::island::pill as island_pill;
use crate::config::workspaces::pill;
use crate::edge::{self, Edge, Part};
use crate::island::{CLEAR, backdrop, faded, mix};
use crate::{theme, tray};
// one round slot per workspace, inside the pill's inset; the pill sits LEFT px from the monitor's edge
const SLOT: f32 = 28.0;
const SLOT_GAP: f32 = 4.0;
const INSET: f32 = 5.0;
const LEFT: f32 = 12.0;
// between the workspaces' pill and the tray's
const TRAY_GAP: f32 = 8.0;
// one round slot per workspace, inside the pill's inset, the pill pill::left() px from the monitor's edge,
// the tray pill::tray_gap() after it (config.rs: workspaces.*)
// each hovered workspace's highlight by workspace id, fading between 0 and 1
#[derive(Default)]
@@ -51,7 +48,7 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
let edge = Edge::read();
let shown = edge.shown(&monitor.name);
(edge::hidden_by(edge.part(Part::Workspaces, &monitor.name), 0.0, HIDE_H), edge::hidden_by(shown, 0.0, HIDE_H), edge.switched(&monitor.name), shown == 0.0)
(edge::hidden_by(edge.part(Part::Workspaces, &monitor.name), 0.0, edge::hide_h()), edge::hidden_by(shown, 0.0, edge::hide_h()), edge.switched(&monitor.name), shown == 0.0)
};
// special workspaces (scratchpads) aren't places to switch to
@@ -63,12 +60,12 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.collect();
let count = here.len() as f32;
let width = 2.0 * INSET + count * SLOT + (count - 1.0).max(0.0) * SLOT_GAP;
let width = 2.0 * pill::inset() + count * pill::slot() + (count - 1.0).max(0.0) * pill::slot_gap();
let window = |window_w: f32| {
LayerWindow::new()
.width(window_w)
.height(TOP_GAP + COMPACT_H + SHADOW)
.height(island_pill::top_gap() + island_pill::height() + island_pill::shadow())
.anchor_vertical(Vertical::Top)
.anchor_horizontal(Horizontal::Left)
// Overlay like the island: on a desktop of fullscreen windows, Top is hidden behind every one of them
@@ -78,15 +75,15 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
};
// empty and click-through rather than hidden: see the island's view for why
if here.is_empty() || slide <= -HIDE_H {
return window(LEFT + width + SHADOW).click_through().child(Rectangle::new().width(0.0).height(0.0));
if here.is_empty() || slide <= -edge::hide_h() {
return window(pill::left() + width + island_pill::shadow()).click_through().child(Rectangle::new().width(0.0).height(0.0));
}
// the tray's pill right of this one (tray.rs), when an app has an icon there; a peek at a workspace change shows the workspaces alone
let tray = if peeking { None } else { tray::pill(&monitor.name, LEFT + width + TRAY_GAP) };
let tray_w = tray.as_ref().map_or(0.0, |(_, tray_w)| TRAY_GAP + tray_w);
let tray = if peeking { None } else { tray::pill(&monitor.name, pill::left() + width + pill::tray_gap()) };
let tray_w = tray.as_ref().map_or(0.0, |(_, tray_w)| pill::tray_gap() + tray_w);
let window = window(LEFT + width + tray_w + SHADOW);
let window = window(pill::left() + width + tray_w + island_pill::shadow());
let mut slots: Vec<Box<dyn Widget>> = Vec::new();
@@ -95,7 +92,7 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
* the workspace before to this one (edge.rs times it); the slots themselves stay clear
*/
let theme = theme::now();
let slot_x = |index: usize| index as f32 * (SLOT + SLOT_GAP);
let slot_x = |index: usize| index as f32 * (pill::slot() + pill::slot_gap());
let focused_at = here.iter().position(|workspace| workspace.focused());
let came_from = switched.and_then(|(from, t)| here.iter().position(|workspace| workspace.id() == from).map(|at| (at, t)));
@@ -137,13 +134,13 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
} else {
let resting = if workspace.windows() > 0 { theme.text } else { theme.dim };
(Color::blend(CLEAR, CHIP_HOVER, lit), Color::blend(resting, theme.text, lit), Weight::Regular)
(Color::blend(CLEAR, overlays::chip_hover(), lit), Color::blend(resting, theme.text, lit), Weight::Regular)
};
slots.push(Box::new(
Rectangle::new()
.width(SLOT)
.height(SLOT)
.width(pill::slot())
.height(pill::slot())
.radius(Full)
.fill(fill)
.align_child(Center, Center)
@@ -151,41 +148,41 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.cursor(Pointer)
.on_hover(move |inside| hovering(id, inside))
.on_click(move |_| focus(id))
.child(Text::new(label).size(12.0).weight(weight).color(color)),
.child(Text::new(label).size(text::body()).weight(weight).color(color)),
));
}
let row_w = width - 2.0 * INSET;
let row_w = width - 2.0 * pill::inset();
// the disc under the focused slot, a little wider while it's on its way
let mut layers: Vec<Box<dyn Widget>> = Vec::new();
if let Some(x) = highlight_x {
layers.push(Box::new(Rectangle::new().width(SLOT + stretch).height(SLOT).radius(Full).fill(theme.accent).translate(x - stretch / 2.0, 0.0)));
layers.push(Box::new(Rectangle::new().width(pill::slot() + stretch).height(pill::slot()).radius(Full).fill(theme.accent).translate(x - stretch / 2.0, 0.0)));
}
layers.push(Box::new(Row::new(slots).gap(SLOT_GAP).align(Center)));
layers.push(Box::new(Row::new(slots).gap(pill::slot_gap()).align(Center)));
let pill = Rectangle::new()
.width(width)
.height(COMPACT_H)
.height(island_pill::height())
.radius(Full)
.fill(backdrop(&theme.surfaces(), 255))
.border(1.0, theme.outline)
.shadow(Shadow::drop(theme.accent).opacity(0.3).blur(22.0))
.padding(INSET)
.padding(pill::inset())
.align_child(Start, Center)
.on_hover(edge::over_bar)
.child(Stack::new(layers).width(row_w).height(SLOT));
.child(Stack::new(layers).width(row_w).height(pill::slot()));
// clicks next to the pills reach the windows underneath
let mut regions = vec![InputArea { x: LEFT as i32, y: TOP_GAP as i32, width: width.ceil() as i32, height: COMPACT_H as i32 }];
let mut regions = vec![InputArea { x: pill::left() as i32, y: island_pill::top_gap() as i32, width: width.ceil() as i32, height: island_pill::height() as i32 }];
let mut pills: Vec<Box<dyn Widget>> = vec![Box::new(pill.translate(0.0, slide))];
// a peek keeps the workspaces in while the bar leaves: the tray slides away on its own
if let Some((tray, tray_pill_w)) = tray {
regions.push(InputArea { x: (LEFT + width + TRAY_GAP) as i32, y: TOP_GAP as i32, width: tray_pill_w.ceil() as i32, height: COMPACT_H as i32 });
regions.push(InputArea { x: (pill::left() + width + pill::tray_gap()) as i32, y: island_pill::top_gap() as i32, width: tray_pill_w.ceil() as i32, height: island_pill::height() as i32 });
pills.push(Box::new(tray.translate(0.0, tray_slide)));
}
@@ -193,9 +190,9 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
Rectangle::new()
.width(Parent)
.height(Parent)
.padding(Padding { top: TOP_GAP, right: 0.0, bottom: 0.0, left: LEFT })
.padding(Padding { top: island_pill::top_gap(), right: 0.0, bottom: 0.0, left: pill::left() })
.align_child(Start, Start)
.child(Row::new(pills).gap(TRAY_GAP).align(Start)),
.child(Row::new(pills).gap(pill::tray_gap()).align(Start)),
)
}
@@ -234,6 +231,6 @@ fn hovering(id: i64, inside: bool) {
hover
.0
.entry(id)
.or_insert_with(|| Animation::new(0.0).duration(Duration::from_millis(HOVER_MS)))
.or_insert_with(|| Animation::new(0.0).duration(Duration::from_millis(motion::hover_ms())))
.to(if inside { 1.0 } else { 0.0 });
}