waydock v0.1: panel, pins, fönstergrupper, menyer, settings-GUI, live-config
Some checks failed
check / check (push) Failing after 52s
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:
180
src/style.rs
Normal file
180
src/style.rs
Normal 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<>k::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
|
||||
}
|
||||
Reference in New Issue
Block a user