waydock v0.1: panel, pins, fönstergrupper, menyer, settings-GUI, live-config
Some checks failed
check / check (push) Failing after 52s

M0–M5 ur doc/plan.md: layer-shell-dock per skärm med transparent
#222222-ö, pins + körande appar (gruppering, badges, indikatorer),
klick/skroll/mittklick, konfigurerbar högerklicksmeny, tomyta-meny,
settings-GUI som redigerar JSON-configen live, filewatcher,
Wayfire-IPC-stubbar (scale, flytta-till-skärm), CI + release-flöde.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 23:24:29 +02:00
commit bc2fa65558
21 changed files with 4579 additions and 0 deletions

180
src/style.rs Normal file
View File

@@ -0,0 +1,180 @@
// Config → CSS. All theming (färger, transparens, skuggor, accent,
// storlekar, animationer) genereras här och laddas i en CssProvider som
// byts ut vid live-omladdning.
use gtk4 as gtk;
use gtk4::gdk;
use crate::config::{Config, IndicatorStyle};
/// "#rrggbb" + alpha → "rgba(r, g, b, a)". Trasig färg → grå.
fn rgba(hex: &str, alpha: f64) -> String {
let h = hex.trim_start_matches('#');
let (r, g, b) = if h.len() == 6 {
(
u8::from_str_radix(&h[0..2], 16).unwrap_or(0x88),
u8::from_str_radix(&h[2..4], 16).unwrap_or(0x88),
u8::from_str_radix(&h[4..6], 16).unwrap_or(0x88),
)
} else {
(0x88, 0x88, 0x88)
};
format!("rgba({r}, {g}, {b}, {alpha:.3})")
}
pub fn build_css(cfg: &Config) -> String {
let a = &cfg.appearance;
let bg = rgba(&a.background, a.opacity);
let border = rgba(&a.border.color, a.border.opacity);
let accent = rgba(&a.accent, 1.0);
let accent_soft = rgba(&a.accent, 0.28);
let shadow = if a.shadow.enabled {
format!(
"box-shadow: 0 2px {}px {};",
a.shadow.blur,
rgba("#000000", a.shadow.opacity)
)
} else {
String::new()
};
let transition = if a.animations {
"transition: all 150ms ease;"
} else {
"transition: none;"
};
let hover_zoom = if a.hover_zoom { "-gtk-icon-transform: scale(1.15);" } else { "" };
let item_pad = (a.icon_spacing / 2).max(0);
let (ind_w, ind_h, ind_radius) = match a.indicator.style {
IndicatorStyle::Dot => (5, 5, 3),
IndicatorStyle::Line => (16, 3, 2),
IndicatorStyle::None => (0, 0, 0),
};
format!(
r#"
window.waydock {{
background: transparent;
}}
.dock-panel {{
background-color: {bg};
border-radius: {radius}px;
border: {bwidth}px solid {border};
padding: {padding}px;
{shadow}
}}
.dock-item {{
background: transparent;
border: none;
border-radius: {item_radius}px;
padding: 4px;
margin: 0 {item_pad}px;
min-width: {icon}px;
min-height: {icon}px;
{transition}
}}
.dock-item:hover {{
background-color: {accent_soft};
}}
.dock-item:hover image {{
{hover_zoom}
}}
.dock-item image {{
{transition}
}}
.dock-item.urgent {{
background-color: {accent_soft};
animation: waydock-pulse 900ms ease-in-out infinite alternate;
}}
@keyframes waydock-pulse {{
from {{ background-color: transparent; }}
to {{ background-color: {accent_soft}; }}
}}
.indicator-box {{
min-height: {ind_h}px;
}}
.indicator {{
background-color: {accent};
border-radius: {ind_radius}px;
min-width: {ind_w}px;
min-height: {ind_h}px;
margin: 0 1px;
}}
.indicator.inactive {{
background-color: {accent_dim};
}}
.group-badge {{
background-color: {accent};
color: #ffffff;
border-radius: 8px;
font-size: 9px;
font-weight: bold;
min-width: 14px;
min-height: 14px;
padding: 0 2px;
}}
popover.waydock-menu contents {{
background-color: {menu_bg};
border-radius: 10px;
border: 1px solid {border};
}}
popover.waydock-menu modelbutton,
popover.waydock-menu button.flat {{
color: #eeeeee;
border-radius: 6px;
padding: 6px 10px;
}}
popover.waydock-menu modelbutton:hover,
popover.waydock-menu button.flat:hover {{
background-color: {accent_soft};
}}
"#,
bg = bg,
radius = a.corner_radius,
bwidth = a.border.width,
border = border,
padding = a.padding,
shadow = shadow,
item_radius = (a.corner_radius as i32 - 4).max(4),
item_pad = item_pad,
icon = a.icon_size + 8,
transition = transition,
hover_zoom = hover_zoom,
accent = accent,
accent_soft = accent_soft,
accent_dim = rgba(&a.accent, 0.45),
ind_h = ind_h,
ind_w = ind_w,
ind_radius = ind_radius,
menu_bg = rgba(&a.background, (a.opacity + 0.2).min(1.0)),
)
}
/// Ladda (eller byt ut) den globala CSS-providern.
pub fn apply(cfg: &Config, previous: Option<&gtk::CssProvider>) -> gtk::CssProvider {
let display = gdk::Display::default().expect("ingen display");
if let Some(old) = previous {
gtk::style_context_remove_provider_for_display(&display, old);
}
let provider = gtk::CssProvider::new();
provider.load_from_string(&build_css(cfg));
gtk::style_context_add_provider_for_display(
&display,
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
provider
}