diff --git a/Cargo.lock b/Cargo.lock index d86226fe..89d965a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1742,6 +1742,7 @@ dependencies = [ "serde", "serde_json", "serde_norway", + "serde_with", "thread-priority", "tracing", "tracing-subscriber", diff --git a/Makefile b/Makefile index 5e0a1f21..5d49708c 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,6 @@ build-release: build-debug: cargo build -p lact -.PHONY: build-release-libadwaita -build-release-libadwaita: - cargo build -p lact --release --features=adw - .PHONY: build-release-headless build-release-headless: cargo build -p lact --release --no-default-features --features=nvidia diff --git a/README.md b/README.md index d6ab798d..a22108a5 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,7 @@ Dependencies: - rust 1.76+ - gtk 4.6+ +- libadwaita 1.5+ - git - pkg-config - clang @@ -221,12 +222,6 @@ Headless build with no GUI: make build-release-headless ``` -Build GUI with libadwaita support: - -``` -make build-release-libadwaita -``` - # Remote management It's possible to have the LACT daemon running on one machine, and then manage it diff --git a/flatpak/startup.sh b/flatpak/startup.sh index d2f986df..5e157dee 100755 --- a/flatpak/startup.sh +++ b/flatpak/startup.sh @@ -85,23 +85,4 @@ WantedBy=multi-user.target\ fi fi -if [ -z "$GTK_THEME" ]; then - set +e - if [ "$(gsettings get org.gnome.desktop.interface gtk-theme)" = "'Adwaita'" ] && [ "$(gsettings get org.gnome.desktop.interface color-scheme)" = "'default'" ]; then - COLOR_SCHEME=$(dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.portal.Settings.Read \ - string:"org.freedesktop.appearance" \ - string:"color-scheme" \ - | grep -oP '(?<=uint32 )\d+') - - if [ "$COLOR_SCHEME" = "1" ]; then - export GTK_THEME="Adwaita:dark" - echo "Detected dark theme system setting, GTK theme overriden to $GTK_THEME" - fi - fi - set -e -fi - lact $@ diff --git a/lact-gui/Cargo.toml b/lact-gui/Cargo.toml index 69889a3c..b12a4508 100644 --- a/lact-gui/Cargo.toml +++ b/lact-gui/Cargo.toml @@ -7,7 +7,6 @@ edition = "2024" [features] default = [] gtk-tests = [] -adw = ["dep:adw", "relm4/libadwaita"] bench = ["dep:divan"] [dependencies] @@ -21,15 +20,16 @@ anyhow = { workspace = true } tracing-subscriber = { workspace = true } chrono = { workspace = true } serde = { workspace = true } +serde_with = { workspace = true } serde_norway = { workspace = true } serde_json = { workspace = true } indexmap = { workspace = true } -gtk = { version = "0.10.0", package = "gtk4", features = ["v4_6"] } +gtk = { version = "0.10.0", package = "gtk4", features = [ + "v4_6", +] } # TODO: bump the feature to 4_14 and figure out all the deprecations -adw = { package = "libadwaita", version = "0.8.0", features = [ - "v1_4", -], optional = true } -relm4 = { version = "0.10.0", default-features = false } +adw = { package = "libadwaita", version = "0.8.0", features = ["v1_5"] } +relm4 = { version = "0.10.0", features = ["libadwaita"] } relm4-components = "0.10.0" i18n-embed = { workspace = true } diff --git a/lact-gui/i18n/en/lact_gui.ftl b/lact-gui/i18n/en/lact_gui.ftl index 21d8bfe3..30e1081e 100644 --- a/lact-gui/i18n/en/lact_gui.ftl +++ b/lact-gui/i18n/en/lact_gui.ftl @@ -248,6 +248,9 @@ profile-rule-process-name = Process Name: profile-rule-args-contain = Arguments Contain: profile-rule-specific-process = With a specific process: +theme = Theme +theme-auto = Automatic + # Crash page crash-page-title = Application Crashed exit = Exit diff --git a/lact-gui/src/app.rs b/lact-gui/src/app.rs index f83dde94..f8c57a29 100644 --- a/lact-gui/src/app.rs +++ b/lact-gui/src/app.rs @@ -28,7 +28,7 @@ use ext::RelmDefaultLauchable; use graphs_window::{GraphsWindow, GraphsWindowMsg}; use gtk::{ ApplicationWindow, ButtonsType, FileChooserAction, FileChooserDialog, MessageDialog, - MessageType, ResponseType, + MessageType, ResponseType, STYLE_PROVIDER_PRIORITY_APPLICATION, glib::{self, ControlFlow, clone}, prelude::{ BoxExt, ButtonExt, Cast, DialogExtManual, FileChooserExt, FileExt, GtkWindowExt, @@ -190,7 +190,14 @@ impl AsyncComponent for AppModel { root: Self::Root, sender: AsyncComponentSender, ) -> AsyncComponentParts { - relm4::set_global_css(styles::COMBINED_CSS); + relm4::set_global_css_with_priority( + styles::COMBINED_CSS, + STYLE_PROVIDER_PRIORITY_APPLICATION, + ); + + if let Err(err) = styles::apply_theme(CONFIG.read().theme) { + error!("could not apply theme: {err:#}"); + } let (daemon_client, conn_err) = match args.tcp_address { Some(remote_addr) => { diff --git a/lact-gui/src/app/header.rs b/lact-gui/src/app/header.rs index d016ffa8..31a15902 100644 --- a/lact-gui/src/app/header.rs +++ b/lact-gui/src/app/header.rs @@ -5,7 +5,12 @@ pub mod profile_rule_window; use crate::{ CONFIG, I18N, - app::{APP_BROKER, header::profile_rule_window::ProfileEditParams, msg::AppMsg}, + app::{ + APP_BROKER, + header::profile_rule_window::ProfileEditParams, + msg::AppMsg, + styles::{self, AppTheme}, + }, config::{MAX_STATS_POLL_INTERVAL_MS, MIN_STATS_POLL_INTERVAL_MS}, }; use glib::clone; @@ -51,6 +56,7 @@ pub enum HeaderMsg { CreateProfile, ImportProfile, ClosePopover, + ThemeSelected(AppTheme), } #[relm4::component(pub)] @@ -153,7 +159,6 @@ impl Component for Header { set_popover = >k::Popover { gtk::Box { set_orientation: gtk::Orientation::Vertical, - set_margin_horizontal: 5, gtk::Button { set_label: &fl!(I18N, "show-historical-charts"), @@ -212,6 +217,8 @@ impl Component for Header { gtk::Box { set_orientation: gtk::Orientation::Horizontal, set_spacing: 5, + set_margin_vertical: 5, + set_halign: gtk::Align::Center, gtk::Label { set_markup: &format!("{}", &fl!(I18N, "stats-update-interval")), @@ -229,6 +236,60 @@ impl Component for Header { } }, }, + + gtk::Separator {}, + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 5, + set_halign: gtk::Align::Center, + set_margin_top: 5, + + gtk::Label { + set_markup: &format!("{}", &fl!(I18N, "theme")), + }, + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + add_css_class: "linked", + + #[name = "theme_auto_btn"] + gtk::ToggleButton { + set_label: &fl!(I18N, "theme-auto"), + #[watch] + set_active: CONFIG.read().theme == AppTheme::Automatic, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(HeaderMsg::ThemeSelected(AppTheme::Automatic)); + } + }, + }, + + gtk::ToggleButton { + set_label: "Adwaita", + set_group: Some(&theme_auto_btn), + #[watch] + set_active: CONFIG.read().theme == AppTheme::Adwaita, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(HeaderMsg::ThemeSelected(AppTheme::Adwaita)); + } + }, + }, + + gtk::ToggleButton { + set_label: "Breeze", + set_group: Some(&theme_auto_btn), + #[watch] + set_active: CONFIG.read().theme == AppTheme::Breeze, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(HeaderMsg::ThemeSelected(AppTheme::Breeze)); + } + }, + }, + }, + }, } }, } @@ -476,6 +537,13 @@ impl Component for Header { HeaderMsg::DeviceInfo(info) => { self.device_flags = info.flags.clone(); } + HeaderMsg::ThemeSelected(theme) => { + styles::apply_theme(theme).expect("Could not apply theme"); + + CONFIG.write().edit(|config| { + config.theme = theme; + }); + } } self.update_label(); diff --git a/lact-gui/src/app/page_section.css b/lact-gui/src/app/page_section.css index 3bb56c70..2dfcd5a4 100644 --- a/lact-gui/src/app/page_section.css +++ b/lact-gui/src/app/page_section.css @@ -1,7 +1,3 @@ -.page-section-content { - border-radius: 5px; -} - .page-section-children-box { margin: 10px; -} +} \ No newline at end of file diff --git a/lact-gui/src/app/page_section.rs b/lact-gui/src/app/page_section.rs index dd2ec16c..c270be74 100644 --- a/lact-gui/src/app/page_section.rs +++ b/lact-gui/src/app/page_section.rs @@ -97,9 +97,7 @@ mod imp { #[local_ref] append = content_box { set_orientation: gtk::Orientation::Vertical, - add_css_class: if cfg!(feature = "adw") { css::CARD } else { "page-section-content" }, - #[watch] - add_css_class: if cfg!(feature = "adw") { "" } else { css::FRAME }, + add_css_class: css::CARD, #[local_ref] append = children_box { diff --git a/lact-gui/src/app/pages/oc_page/clocks_frame.css b/lact-gui/src/app/pages/oc_page/clocks_frame.css index 97434c35..7e5490a3 100644 --- a/lact-gui/src/app/pages/oc_page/clocks_frame.css +++ b/lact-gui/src/app/pages/oc_page/clocks_frame.css @@ -1,7 +1,3 @@ -.clocks-frame > .page-section-content { - border-color: transparent; -} - .clocks-frame .page-section-children-box { margin: 0; } @@ -13,5 +9,4 @@ .clocks-frame-group .frame { border-radius: 5px; padding: 10px; -} - +} \ No newline at end of file diff --git a/lact-gui/src/app/styles.rs b/lact-gui/src/app/styles.rs index feee0c3e..eae328f8 100644 --- a/lact-gui/src/app/styles.rs +++ b/lact-gui/src/app/styles.rs @@ -1,5 +1,84 @@ +use gtk::{ + gio::{self, prelude::SettingsExt}, + style_context_add_provider_for_display, style_context_remove_provider_for_display, +}; +use serde::{Deserialize, Serialize}; +use std::cell::RefCell; + pub const COMBINED_CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/combined.css")); +macro_rules! include_theme_str { + ($file:literal) => { + include_str!(concat!( + concat!(env!("CARGO_MANIFEST_DIR"), "/themes/",), + $file + )) + }; +} + +const BREEZE_DARK_CSS: &str = include_theme_str!("breeze-dark.css"); +const BREEZE_LIGHT_CSS: &str = include_theme_str!("breeze-light.css"); + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum AppTheme { + #[default] + Automatic, + Adwaita, + Breeze, +} + +thread_local! { + static EXISTING_STYLE_PROVIDER: RefCell> = const { RefCell::new(None) }; +} + +pub fn apply_theme(theme: AppTheme) -> anyhow::Result<()> { + let display = gtk::gdk::Display::default().unwrap(); + + if let Some(existing_style_provider) = EXISTING_STYLE_PROVIDER.take() { + style_context_remove_provider_for_display(&display, &existing_style_provider); + } + + let theme_css = match theme { + AppTheme::Automatic => { + let settings = gio::Settings::new("org.gnome.desktop.interface"); + let system_theme = settings.string("gtk-theme").to_ascii_lowercase(); + + if matches!( + system_theme.as_str(), + "breeze" | "breeze-light" | "breeze-dark" + ) { + Some(breeze_css()) + } else { + None + } + } + AppTheme::Adwaita => None, + AppTheme::Breeze => Some(breeze_css()), + }; + + if let Some(css) = theme_css { + let provider = gtk::CssProvider::new(); + #[allow(deprecated)] + provider.load_from_data(css); + + style_context_add_provider_for_display(&display, &provider, 900); + + EXISTING_STYLE_PROVIDER.set(Some(provider)); + } + + Ok(()) +} + +fn breeze_css() -> &'static str { + let settings = gio::Settings::new("org.gnome.desktop.interface"); + match settings.string("color-scheme").as_str() { + "prefer-dark" => BREEZE_DARK_CSS, + "prefer-light" => BREEZE_LIGHT_CSS, + _ => BREEZE_LIGHT_CSS, + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/lact-gui/src/config.rs b/lact-gui/src/config.rs index 82a41bb7..71de398c 100644 --- a/lact-gui/src/config.rs +++ b/lact-gui/src/config.rs @@ -1,20 +1,19 @@ -use crate::app::graphs_window::stat::StatType; +use crate::app::{graphs_window::stat::StatType, styles::AppTheme}; use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; use std::{collections::HashMap, env, fs, path::PathBuf}; use tracing::{debug, error}; pub const MIN_STATS_POLL_INTERVAL_MS: i64 = 250; pub const MAX_STATS_POLL_INTERVAL_MS: i64 = 5000; +#[skip_serializing_none] #[derive(Serialize, Deserialize)] pub struct UiConfig { #[serde(default = "default_tab")] pub selected_tab: String, - #[serde(default, skip_serializing_if = "Option::is_none")] pub selected_gpu: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] pub plots_time_period: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] pub plots_per_row: Option, #[serde( default = "default_stats_poll_interval", @@ -23,6 +22,8 @@ pub struct UiConfig { pub stats_poll_interval_ms: i64, #[serde(default)] pub gpus: HashMap, + #[serde(default)] + pub theme: AppTheme, } impl Default for UiConfig { @@ -34,6 +35,7 @@ impl Default for UiConfig { plots_per_row: None, stats_poll_interval_ms: default_stats_poll_interval(), gpus: HashMap::new(), + theme: AppTheme::Automatic, } } } diff --git a/lact-gui/themes/breeze-dark.css b/lact-gui/themes/breeze-dark.css new file mode 100644 index 00000000..2f2637ac --- /dev/null +++ b/lact-gui/themes/breeze-dark.css @@ -0,0 +1,509 @@ +/* + * Breeze Dark color theme + * Extracted from KDE Breeze-Dark GTK 4.0 theme + * Only color properties — layout is left to libadwaita + */ + +/* =================== + * Breeze color palette + * =================== */ + +/* Foreground / text */ +@define-color theme_fg_color_breeze #fcfcfc; +@define-color theme_text_color_breeze #fcfcfc; + +/* Backgrounds */ +@define-color theme_bg_color_breeze #202326; +@define-color theme_base_color_breeze #141618; +@define-color content_view_bg_breeze #141618; + +/* Selection / accent */ +@define-color theme_selected_bg_color_breeze #3daee9; +@define-color theme_selected_fg_color_breeze #fcfcfc; +@define-color theme_hovering_selected_bg_color_breeze #3daee9; +@define-color theme_view_hover_decoration_color_breeze #3daee9; +@define-color theme_view_active_decoration_color_breeze #3daee9; + +/* Insensitive */ +@define-color insensitive_bg_color_breeze #1d2023; +@define-color insensitive_fg_color_breeze rgba(229, 229, 229, 0.35); +@define-color insensitive_base_color_breeze rgba(229, 229, 229, 0.35); +@define-color insensitive_base_fg_color_breeze #121416; +@define-color insensitive_selected_bg_color_breeze rgba(37, 164, 230, 0.35); +@define-color insensitive_selected_fg_color_breeze rgba(229, 229, 229, 0.35); + +/* Unfocused / backdrop */ +@define-color theme_unfocused_fg_color_breeze #fcfcfc; +@define-color theme_unfocused_text_color_breeze #fcfcfc; +@define-color theme_unfocused_bg_color_breeze #202326; +@define-color theme_unfocused_base_color_breeze #141618; +@define-color theme_unfocused_selected_bg_color_alt_breeze #3daee9; +@define-color theme_unfocused_selected_bg_color_breeze rgba(61, 174, 233, 0.5); +@define-color theme_unfocused_selected_fg_color_breeze #fcfcfc; +@define-color theme_unfocused_view_text_color_breeze rgba(229, 229, 229, 0.35); +@define-color theme_unfocused_view_bg_color_breeze #121416; +@define-color insensitive_unfocused_selected_bg_color_breeze rgba(37, 164, 230, 0.35); +@define-color insensitive_unfocused_fg_color_breeze rgba(229, 229, 229, 0.35); +@define-color insensitive_unfocused_bg_color_breeze #1d2023; +@define-color insensitive_unfocused_selected_fg_color_breeze rgba(229, 229, 229, 0.35); + +/* Borders */ +@define-color borders_breeze #4c4e51; +@define-color unfocused_borders_breeze #4c4e51; +@define-color insensitive_borders_breeze rgba(69, 71, 74, 0.35); +@define-color unfocused_insensitive_borders_breeze rgba(69, 71, 74, 0.35); + +/* Buttons */ +@define-color theme_button_background_normal_breeze #292c30; +@define-color theme_button_decoration_hover_breeze #3daee9; +@define-color theme_button_decoration_focus_breeze #3daee9; +@define-color theme_button_foreground_normal_breeze #fcfcfc; +@define-color theme_button_foreground_active_breeze #fcfcfc; +@define-color theme_button_background_insensitive_breeze rgba(37, 40, 44, 0.35); +@define-color theme_button_decoration_hover_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_decoration_focus_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_foreground_insensitive_breeze rgba(229, 229, 229, 0.35); +@define-color theme_button_foreground_active_insensitive_breeze rgba(229, 229, 229, 0.35); +@define-color theme_button_background_backdrop_breeze #292c30; +@define-color theme_button_decoration_hover_backdrop_breeze #3daee9; +@define-color theme_button_decoration_focus_backdrop_breeze #3daee9; +@define-color theme_button_foreground_backdrop_breeze #fcfcfc; +@define-color theme_button_foreground_active_backdrop_breeze #fcfcfc; +@define-color theme_button_background_backdrop_insensitive_breeze rgba(37, 40, 44, 0.35); +@define-color theme_button_decoration_hover_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_decoration_focus_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_foreground_backdrop_insensitive_breeze rgba(229, 229, 229, 0.35); +@define-color theme_button_foreground_active_backdrop_insensitive_breeze rgba(229, 229, 229, 0.35); + +/* Status colors */ +@define-color warning_color_breeze #f67400; +@define-color error_color_breeze #da4453; +@define-color success_color_breeze #27ae60; +@define-color warning_color_backdrop_breeze #f67400; +@define-color error_color_backdrop_breeze #da4453; +@define-color success_color_backdrop_breeze #27ae60; +@define-color warning_color_insensitive_breeze rgba(224, 105, 0, 0.35); +@define-color error_color_insensitive_breeze rgba(214, 46, 63, 0.35); +@define-color success_color_insensitive_breeze rgba(35, 158, 87, 0.35); +@define-color warning_color_insensitive_backdrop_breeze rgba(224, 105, 0, 0.35); +@define-color error_color_insensitive_backdrop_breeze rgba(214, 46, 63, 0.35); +@define-color success_color_insensitive_backdrop_breeze rgba(35, 158, 87, 0.35); + +/* Links */ +@define-color link_color_breeze #1d99f3; +@define-color link_visited_color_breeze #9b59b6; + +/* Titlebar */ +@define-color theme_titlebar_background_breeze #272c31; +@define-color theme_titlebar_foreground_breeze #fcfcfc; +@define-color theme_titlebar_background_light_breeze #202326; +@define-color theme_titlebar_foreground_backdrop_breeze #a1a9b1; +@define-color theme_titlebar_background_backdrop_breeze #202428; +@define-color theme_titlebar_foreground_insensitive_breeze rgba(229, 229, 229, 0.35); +@define-color theme_titlebar_foreground_insensitive_backdrop_breeze rgba(144, 154, 163, 0.35); + +/* Tooltips */ +@define-color tooltip_text_breeze #fcfcfc; +@define-color tooltip_background_breeze #292c30; +@define-color tooltip_border_breeze #535659; + + +/* ============================== + * libadwaita color overrides + * ============================== */ + +/* Accent — Breeze KDE blue */ +@define-color accent_bg_color @theme_selected_bg_color_breeze; +@define-color accent_fg_color @theme_selected_fg_color_breeze; +@define-color accent_color @theme_selected_bg_color_breeze; + +/* Window */ +@define-color window_bg_color @theme_bg_color_breeze; +@define-color window_fg_color @theme_fg_color_breeze; + +/* Views / content areas */ +@define-color view_bg_color @theme_base_color_breeze; +@define-color view_fg_color @theme_text_color_breeze; + +/* Headerbar */ +@define-color headerbar_bg_color @theme_titlebar_background_breeze; +@define-color headerbar_fg_color @theme_titlebar_foreground_breeze; +@define-color headerbar_border_color @theme_titlebar_foreground_breeze; +@define-color headerbar_backdrop_color @theme_titlebar_background_backdrop_breeze; +@define-color headerbar_shade_color rgba(0, 0, 0, 0.36); +@define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.9); + +/* Sidebar */ +@define-color sidebar_bg_color @theme_button_background_normal_breeze; +@define-color sidebar_fg_color @theme_fg_color_breeze; +@define-color sidebar_backdrop_color #252830; +@define-color sidebar_shade_color rgba(0, 0, 0, 0.25); +@define-color sidebar_border_color rgba(0, 0, 0, 0.36); + +/* Secondary sidebar */ +@define-color secondary_sidebar_bg_color #252830; +@define-color secondary_sidebar_fg_color @theme_fg_color_breeze; +@define-color secondary_sidebar_backdrop_color @theme_bg_color_breeze; +@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.25); +@define-color secondary_sidebar_border_color rgba(0, 0, 0, 0.36); + +/* Cards */ +@define-color card_bg_color rgba(255, 255, 255, 0.05); +@define-color card_fg_color @theme_fg_color_breeze; +@define-color card_shade_color rgba(0, 0, 0, 0.36); + +/* Dialogs & popovers */ +@define-color dialog_bg_color @theme_button_background_normal_breeze; +@define-color dialog_fg_color @theme_fg_color_breeze; +@define-color popover_bg_color @theme_button_background_normal_breeze; +@define-color popover_fg_color @theme_fg_color_breeze; +@define-color popover_shade_color rgba(0, 0, 0, 0.25); + +/* Thumbnails */ +@define-color thumbnail_bg_color #303338; +@define-color thumbnail_fg_color @theme_fg_color_breeze; + +/* Misc */ +@define-color shade_color rgba(0, 0, 0, 0.25); +@define-color scrollbar_outline_color rgba(0, 0, 0, 0.5); + +/* Status colors — libadwaita */ +@define-color destructive_bg_color @error_color_breeze; +@define-color destructive_fg_color white; +@define-color destructive_color @error_color_breeze; +@define-color success_bg_color @success_color_breeze; +@define-color success_fg_color white; +@define-color success_color @success_color_breeze; +@define-color warning_bg_color @warning_color_breeze; +@define-color warning_fg_color white; +@define-color warning_color @warning_color_breeze; +@define-color error_bg_color @error_color_breeze; +@define-color error_fg_color white; +@define-color error_color @error_color_breeze; + + +/* ============================== + * GTK standard color aliases + * ============================== */ + +@define-color theme_fg_color @theme_fg_color_breeze; +@define-color theme_text_color @theme_text_color_breeze; +@define-color theme_bg_color @theme_bg_color_breeze; +@define-color theme_base_color @theme_base_color_breeze; +@define-color theme_selected_bg_color @theme_selected_bg_color_breeze; +@define-color theme_selected_fg_color @theme_selected_fg_color_breeze; +@define-color insensitive_bg_color @insensitive_bg_color_breeze; +@define-color insensitive_fg_color @insensitive_fg_color_breeze; +@define-color insensitive_base_color @insensitive_base_color_breeze; +@define-color theme_unfocused_fg_color @theme_unfocused_fg_color_breeze; +@define-color theme_unfocused_text_color @theme_unfocused_text_color_breeze; +@define-color theme_unfocused_bg_color @theme_unfocused_bg_color_breeze; +@define-color theme_unfocused_base_color @theme_unfocused_base_color_breeze; +@define-color theme_unfocused_selected_bg_color @theme_unfocused_selected_bg_color_breeze; +@define-color theme_unfocused_selected_fg_color @theme_unfocused_selected_fg_color_breeze; +@define-color unfocused_insensitive_color @insensitive_unfocused_bg_color_breeze; +@define-color borders @borders_breeze; +@define-color unfocused_borders @unfocused_borders_breeze; +@define-color content_view_bg @content_view_bg_breeze; +@define-color text_view_bg @content_view_bg_breeze; + + +/* ============================== + * Button shapes & colors + * ============================== */ + +/* --- Regular buttons --- */ + +button { + border-radius: 3px; + outline: 1px solid @borders_breeze; + outline-offset: -1px; + background: @theme_button_background_normal_breeze; + color: @theme_button_foreground_normal_breeze; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125); + text-shadow: none; + -gtk-icon-shadow: none; + font-weight: normal; +} + +button:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +button:active { + box-shadow: none; + background: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +button:checked { + background: alpha(@theme_button_foreground_normal_breeze, 0.125); + box-shadow: none; +} + +button:focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +button:backdrop { + box-shadow: none; +} + +button:disabled { + box-shadow: none; + color: @theme_button_foreground_insensitive_breeze; + outline-color: @insensitive_borders_breeze; + background: @theme_button_background_insensitive_breeze; +} + +button:disabled:active, +button:disabled:checked { + color: @theme_button_foreground_active_insensitive_breeze; +} + +/* --- Suggested & destructive: subtle tint instead of solid fill --- */ + +button.suggested-action, +button.flat.suggested-action { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.2); + outline-color: mix(@theme_button_decoration_focus_breeze, + mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.333), 0.5); +} + +button.destructive-action, +button.flat.destructive-action { + background-color: alpha(@error_color_breeze, 0.2); + outline-color: mix(@error_color_breeze, + mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.333), 0.5); +} + +button.suggested-action:hover { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.35); + outline-color: @theme_button_decoration_focus_breeze; +} + +button.destructive-action:hover { + background-color: alpha(@error_color_breeze, 0.35); + outline-color: @error_color_breeze; +} + +button.suggested-action:active { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.5); +} + +button.destructive-action:active { + background-color: alpha(@error_color_breeze, 0.5); +} + +/* --- Flat buttons --- */ + +button.flat { + outline-color: transparent; + background: transparent; + box-shadow: none; +} + +button.flat:checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +button.flat:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +button.flat:active { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +/* --- Circular buttons --- */ + +button.circular { + border-radius: 9999px; +} + +/* --- Headerbar buttons (flat by default, like Breeze) --- */ + +headerbar button:not(.suggested-action):not(.destructive-action) { + outline-color: transparent; + background: transparent; + box-shadow: none; + color: @theme_titlebar_foreground_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +headerbar button:not(.suggested-action):not(.destructive-action):hover { + outline-color: @theme_button_decoration_hover_breeze; + color: @theme_titlebar_foreground_breeze; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.08); +} + +headerbar button:not(.suggested-action):not(.destructive-action):active { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +headerbar button:not(.suggested-action):not(.destructive-action):focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):backdrop { + color: @theme_titlebar_foreground_backdrop_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):backdrop:checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +headerbar button:not(.suggested-action):not(.destructive-action):disabled { + color: @theme_titlebar_foreground_insensitive_breeze; +} + +/* Headerbar tab buttons (stack switcher) — visible so they look interactive */ + +headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked) { + outline-color: alpha(@borders_breeze, 0.6); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.06); +} + +headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked):hover { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.08); +} + +/* Headerbar linked buttons — restore regular button look */ + +headerbar .linked button { + color: @theme_button_foreground_normal_breeze; + outline-color: @borders_breeze; + background: @theme_button_background_normal_breeze; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125); +} + +/* --- SpinButton +/- buttons: flat, only icon colour changes on disable --- */ + +spinbutton:not(.vertical) button, +spinbutton:not(.vertical) button:disabled { + background: transparent; + outline-color: transparent; + box-shadow: none; +} + +spinbutton:not(.vertical) button:hover { + color: @theme_view_hover_decoration_color_breeze; +} + +spinbutton:not(.vertical) button:active { + background: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +spinbutton:not(.vertical) button:disabled { + color: @theme_button_foreground_insensitive_breeze; +} + +/* --- Check & radio indicators --- */ + +check, +radio { + background-color: @theme_base_color_breeze; + outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.333); + outline-offset: -1px; + -gtk-icon-shadow: none; +} + +check { + border-radius: 3px; +} + +radio { + border-radius: 50%; +} + +check:hover, +radio:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +check:focus, +radio:focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +check:checked, +check:indeterminate, +radio:checked, +radio:indeterminate { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +check:disabled, +radio:disabled { + background-color: alpha(@theme_base_color_breeze, 0.03); + outline-color: alpha(@theme_button_foreground_normal_breeze, 0.222); +} + +check:checked:disabled, +check:indeterminate:disabled, +radio:checked:disabled, +radio:indeterminate:disabled { + background-color: alpha(@theme_button_foreground_normal_breeze, 0.03); + outline-color: alpha(@theme_button_decoration_hover_breeze, 0.3); +} + +/* --- Switch --- */ + +switch { + outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.222); + outline-offset: -1px; + border-radius: 12px; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.05); + color: transparent; +} + +switch:checked { + background: alpha(@theme_button_decoration_hover_breeze, 0.333); + outline-color: @theme_button_decoration_hover_breeze; +} + +switch:disabled { + background-color: alpha(@theme_button_foreground_normal_breeze, 0.03); +} + +switch:checked:disabled { + background: alpha(@theme_button_decoration_hover_breeze, 0.222); + outline-color: alpha(@theme_button_decoration_hover_breeze, 0.777); +} + +switch slider { + outline: 1px solid @borders_breeze; + outline-offset: -1px; + border-radius: 12px; + background: @theme_button_background_normal_breeze; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.125); +} + +switch:hover slider { + outline-color: @theme_button_decoration_hover_breeze; +} + +switch:focus slider { + outline-color: @theme_button_decoration_focus_breeze; +} + +switch:disabled slider { + box-shadow: none; + color: @theme_button_foreground_insensitive_breeze; + outline-color: @insensitive_borders_breeze; + background: @theme_button_background_insensitive_breeze; +} diff --git a/lact-gui/themes/breeze-light.css b/lact-gui/themes/breeze-light.css new file mode 100644 index 00000000..049d0e30 --- /dev/null +++ b/lact-gui/themes/breeze-light.css @@ -0,0 +1,509 @@ +/* + * Breeze Light color theme + * Extracted from KDE Breeze GTK 4.0 theme + * Only color properties — layout is left to libadwaita + */ + +/* =================== + * Breeze color palette + * =================== */ + +/* Foreground / text */ +@define-color theme_fg_color_breeze #232629; +@define-color theme_text_color_breeze #232629; + +/* Backgrounds */ +@define-color theme_bg_color_breeze #eff0f1; +@define-color theme_base_color_breeze white; +@define-color content_view_bg_breeze white; + +/* Selection / accent */ +@define-color theme_selected_bg_color_breeze #3daee9; +@define-color theme_selected_fg_color_breeze white; +@define-color theme_hovering_selected_bg_color_breeze #3daee9; +@define-color theme_view_hover_decoration_color_breeze #3daee9; +@define-color theme_view_active_decoration_color_breeze #3daee9; + +/* Insensitive */ +@define-color insensitive_bg_color_breeze #d8dadd; +@define-color insensitive_fg_color_breeze rgba(32, 35, 37, 0.35); +@define-color insensitive_base_color_breeze rgba(32, 35, 37, 0.35); +@define-color insensitive_base_fg_color_breeze #e8e8e8; +@define-color insensitive_selected_bg_color_breeze rgba(37, 164, 230, 0.35); +@define-color insensitive_selected_fg_color_breeze #e8e8e8; + +/* Unfocused / backdrop */ +@define-color theme_unfocused_fg_color_breeze #232629; +@define-color theme_unfocused_text_color_breeze #232629; +@define-color theme_unfocused_bg_color_breeze #eff0f1; +@define-color theme_unfocused_base_color_breeze white; +@define-color theme_unfocused_selected_bg_color_alt_breeze #3daee9; +@define-color theme_unfocused_selected_bg_color_breeze rgba(61, 174, 233, 0.5); +@define-color theme_unfocused_selected_fg_color_breeze white; +@define-color theme_unfocused_view_text_color_breeze rgba(32, 35, 37, 0.35); +@define-color theme_unfocused_view_bg_color_breeze #e8e8e8; +@define-color insensitive_unfocused_selected_bg_color_breeze rgba(37, 164, 230, 0.35); +@define-color insensitive_unfocused_fg_color_breeze rgba(32, 35, 37, 0.35); +@define-color insensitive_unfocused_bg_color_breeze #d8dadd; +@define-color insensitive_unfocused_selected_fg_color_breeze #e8e8e8; + +/* Borders */ +@define-color borders_breeze #c6c8c9; +@define-color unfocused_borders_breeze #c6c8c9; +@define-color insensitive_borders_breeze rgba(179, 182, 183, 0.35); +@define-color unfocused_insensitive_borders_breeze rgba(179, 182, 183, 0.35); + +/* Buttons */ +@define-color theme_button_background_normal_breeze #fcfcfc; +@define-color theme_button_decoration_hover_breeze #3daee9; +@define-color theme_button_decoration_focus_breeze #3daee9; +@define-color theme_button_foreground_normal_breeze #232629; +@define-color theme_button_foreground_active_breeze white; +@define-color theme_button_background_insensitive_breeze #e5e5e5; +@define-color theme_button_decoration_hover_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_decoration_focus_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_foreground_insensitive_breeze rgba(32, 35, 37, 0.35); +@define-color theme_button_foreground_active_insensitive_breeze #e8e8e8; +@define-color theme_button_background_backdrop_breeze #fcfcfc; +@define-color theme_button_decoration_hover_backdrop_breeze #3daee9; +@define-color theme_button_decoration_focus_backdrop_breeze #3daee9; +@define-color theme_button_foreground_backdrop_breeze #232629; +@define-color theme_button_foreground_active_backdrop_breeze white; +@define-color theme_button_background_backdrop_insensitive_breeze #e5e5e5; +@define-color theme_button_decoration_hover_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_decoration_focus_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35); +@define-color theme_button_foreground_backdrop_insensitive_breeze rgba(32, 35, 37, 0.35); +@define-color theme_button_foreground_active_backdrop_insensitive_breeze #e8e8e8; + +/* Status colors */ +@define-color warning_color_breeze #f67400; +@define-color error_color_breeze #da4453; +@define-color success_color_breeze #27ae60; +@define-color warning_color_backdrop_breeze #f67400; +@define-color error_color_backdrop_breeze #da4453; +@define-color success_color_backdrop_breeze #27ae60; +@define-color warning_color_insensitive_breeze rgba(224, 105, 0, 0.35); +@define-color error_color_insensitive_breeze rgba(214, 46, 63, 0.35); +@define-color success_color_insensitive_breeze rgba(35, 158, 87, 0.35); +@define-color warning_color_insensitive_backdrop_breeze rgba(224, 105, 0, 0.35); +@define-color error_color_insensitive_backdrop_breeze rgba(214, 46, 63, 0.35); +@define-color success_color_insensitive_backdrop_breeze rgba(35, 158, 87, 0.35); + +/* Links */ +@define-color link_color_breeze #2980b9; +@define-color link_visited_color_breeze #9b59b6; + +/* Titlebar */ +@define-color theme_titlebar_background_breeze #e3e5e7; +@define-color theme_titlebar_foreground_breeze #232629; +@define-color theme_titlebar_background_light_breeze #eff0f1; +@define-color theme_titlebar_foreground_backdrop_breeze #707d8a; +@define-color theme_titlebar_background_backdrop_breeze #eff0f1; +@define-color theme_titlebar_foreground_insensitive_breeze rgba(32, 35, 37, 0.35); +@define-color theme_titlebar_foreground_insensitive_backdrop_breeze rgba(102, 114, 125, 0.35); + +/* Tooltips */ +@define-color tooltip_text_breeze #232629; +@define-color tooltip_background_breeze #f7f7f7; +@define-color tooltip_border_breeze #cdcdce; + + +/* ============================== + * libadwaita color overrides + * ============================== */ + +/* Accent — Breeze KDE blue */ +@define-color accent_bg_color @theme_selected_bg_color_breeze; +@define-color accent_fg_color @theme_selected_fg_color_breeze; +@define-color accent_color @theme_selected_bg_color_breeze; + +/* Window */ +@define-color window_bg_color @theme_bg_color_breeze; +@define-color window_fg_color @theme_fg_color_breeze; + +/* Views / content areas */ +@define-color view_bg_color @theme_base_color_breeze; +@define-color view_fg_color @theme_text_color_breeze; + +/* Headerbar */ +@define-color headerbar_bg_color @theme_titlebar_background_breeze; +@define-color headerbar_fg_color @theme_titlebar_foreground_breeze; +@define-color headerbar_border_color @theme_titlebar_foreground_breeze; +@define-color headerbar_backdrop_color @theme_titlebar_background_backdrop_breeze; +@define-color headerbar_shade_color rgba(0, 0, 0, 0.07); +@define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.07); + +/* Sidebar */ +@define-color sidebar_bg_color #e3e5e7; +@define-color sidebar_fg_color @theme_fg_color_breeze; +@define-color sidebar_backdrop_color #eaebec; +@define-color sidebar_shade_color rgba(0, 0, 0, 0.07); +@define-color sidebar_border_color rgba(0, 0, 0, 0.07); + +/* Secondary sidebar */ +@define-color secondary_sidebar_bg_color #eaebec; +@define-color secondary_sidebar_fg_color @theme_fg_color_breeze; +@define-color secondary_sidebar_backdrop_color @theme_bg_color_breeze; +@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.07); +@define-color secondary_sidebar_border_color rgba(0, 0, 0, 0.07); + +/* Cards */ +@define-color card_bg_color white; +@define-color card_fg_color @theme_fg_color_breeze; +@define-color card_shade_color rgba(0, 0, 0, 0.07); + +/* Dialogs & popovers */ +@define-color dialog_bg_color @theme_bg_color_breeze; +@define-color dialog_fg_color @theme_fg_color_breeze; +@define-color popover_bg_color white; +@define-color popover_fg_color @theme_fg_color_breeze; +@define-color popover_shade_color rgba(0, 0, 0, 0.07); + +/* Thumbnails */ +@define-color thumbnail_bg_color white; +@define-color thumbnail_fg_color @theme_fg_color_breeze; + +/* Misc */ +@define-color shade_color rgba(0, 0, 0, 0.07); +@define-color scrollbar_outline_color white; + +/* Status colors — libadwaita */ +@define-color destructive_bg_color @error_color_breeze; +@define-color destructive_fg_color white; +@define-color destructive_color @error_color_breeze; +@define-color success_bg_color @success_color_breeze; +@define-color success_fg_color white; +@define-color success_color @success_color_breeze; +@define-color warning_bg_color @warning_color_breeze; +@define-color warning_fg_color white; +@define-color warning_color @warning_color_breeze; +@define-color error_bg_color @error_color_breeze; +@define-color error_fg_color white; +@define-color error_color @error_color_breeze; + + +/* ============================== + * GTK standard color aliases + * ============================== */ + +@define-color theme_fg_color @theme_fg_color_breeze; +@define-color theme_text_color @theme_text_color_breeze; +@define-color theme_bg_color @theme_bg_color_breeze; +@define-color theme_base_color @theme_base_color_breeze; +@define-color theme_selected_bg_color @theme_selected_bg_color_breeze; +@define-color theme_selected_fg_color @theme_selected_fg_color_breeze; +@define-color insensitive_bg_color @insensitive_bg_color_breeze; +@define-color insensitive_fg_color @insensitive_fg_color_breeze; +@define-color insensitive_base_color @insensitive_base_color_breeze; +@define-color theme_unfocused_fg_color @theme_unfocused_fg_color_breeze; +@define-color theme_unfocused_text_color @theme_unfocused_text_color_breeze; +@define-color theme_unfocused_bg_color @theme_unfocused_bg_color_breeze; +@define-color theme_unfocused_base_color @theme_unfocused_base_color_breeze; +@define-color theme_unfocused_selected_bg_color @theme_unfocused_selected_bg_color_breeze; +@define-color theme_unfocused_selected_fg_color @theme_unfocused_selected_fg_color_breeze; +@define-color unfocused_insensitive_color @insensitive_unfocused_bg_color_breeze; +@define-color borders @borders_breeze; +@define-color unfocused_borders @unfocused_borders_breeze; +@define-color content_view_bg @content_view_bg_breeze; +@define-color text_view_bg @content_view_bg_breeze; + + +/* ============================== + * Button shapes & colors + * ============================== */ + +/* --- Regular buttons --- */ + +button { + border-radius: 3px; + outline: 1px solid @borders_breeze; + outline-offset: -1px; + background: @theme_button_background_normal_breeze; + color: @theme_button_foreground_normal_breeze; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125); + text-shadow: none; + -gtk-icon-shadow: none; + font-weight: normal; +} + +button:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +button:active { + box-shadow: none; + background: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +button:checked { + background: alpha(@theme_button_foreground_normal_breeze, 0.125); + box-shadow: none; +} + +button:focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +button:backdrop { + box-shadow: none; +} + +button:disabled { + box-shadow: none; + color: @theme_button_foreground_insensitive_breeze; + outline-color: @insensitive_borders_breeze; + background: @theme_button_background_insensitive_breeze; +} + +button:disabled:active, +button:disabled:checked { + color: @theme_button_foreground_active_insensitive_breeze; +} + +/* --- Suggested & destructive: subtle tint instead of solid fill --- */ + +button.suggested-action, +button.flat.suggested-action { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.2); + outline-color: mix(@theme_button_decoration_focus_breeze, + mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.333), 0.5); +} + +button.destructive-action, +button.flat.destructive-action { + background-color: alpha(@error_color_breeze, 0.2); + outline-color: mix(@error_color_breeze, + mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.333), 0.5); +} + +button.suggested-action:hover { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.35); + outline-color: @theme_button_decoration_focus_breeze; +} + +button.destructive-action:hover { + background-color: alpha(@error_color_breeze, 0.35); + outline-color: @error_color_breeze; +} + +button.suggested-action:active { + background-color: alpha(@theme_button_decoration_focus_breeze, 0.5); +} + +button.destructive-action:active { + background-color: alpha(@error_color_breeze, 0.5); +} + +/* --- Flat buttons --- */ + +button.flat { + outline-color: transparent; + background: transparent; + box-shadow: none; +} + +button.flat:checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +button.flat:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +button.flat:active { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +/* --- Circular buttons --- */ + +button.circular { + border-radius: 9999px; +} + +/* --- Headerbar buttons (flat by default, like Breeze) --- */ + +headerbar button:not(.suggested-action):not(.destructive-action) { + outline-color: transparent; + background: transparent; + box-shadow: none; + color: @theme_titlebar_foreground_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +headerbar button:not(.suggested-action):not(.destructive-action):hover { + outline-color: @theme_button_decoration_hover_breeze; + color: @theme_titlebar_foreground_breeze; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.08); +} + +headerbar button:not(.suggested-action):not(.destructive-action):active { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +headerbar button:not(.suggested-action):not(.destructive-action):focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):backdrop { + color: @theme_titlebar_foreground_backdrop_breeze; +} + +headerbar button:not(.suggested-action):not(.destructive-action):backdrop:checked { + outline-color: mix(@theme_button_background_normal_breeze, + @theme_button_foreground_normal_breeze, 0.3); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.125); +} + +headerbar button:not(.suggested-action):not(.destructive-action):disabled { + color: @theme_titlebar_foreground_insensitive_breeze; +} + +/* Headerbar tab buttons (stack switcher) — visible so they look interactive */ + +headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked) { + outline-color: alpha(@borders_breeze, 0.6); + background-color: alpha(@theme_button_foreground_normal_breeze, 0.06); +} + +headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked):hover { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.08); +} + +/* Headerbar linked buttons — restore regular button look */ + +headerbar .linked button { + color: @theme_button_foreground_normal_breeze; + outline-color: @borders_breeze; + background: @theme_button_background_normal_breeze; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125); +} + +/* --- SpinButton +/- buttons: flat, only icon colour changes on disable --- */ + +spinbutton:not(.vertical) button, +spinbutton:not(.vertical) button:disabled { + background: transparent; + outline-color: transparent; + box-shadow: none; +} + +spinbutton:not(.vertical) button:hover { + color: @theme_view_hover_decoration_color_breeze; +} + +spinbutton:not(.vertical) button:active { + background: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +spinbutton:not(.vertical) button:disabled { + color: @theme_button_foreground_insensitive_breeze; +} + +/* --- Check & radio indicators --- */ + +check, +radio { + background-color: @theme_base_color_breeze; + outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.333); + outline-offset: -1px; + -gtk-icon-shadow: none; +} + +check { + border-radius: 3px; +} + +radio { + border-radius: 50%; +} + +check:hover, +radio:hover { + outline-color: @theme_button_decoration_hover_breeze; +} + +check:focus, +radio:focus { + outline-color: @theme_button_decoration_focus_breeze; +} + +check:checked, +check:indeterminate, +radio:checked, +radio:indeterminate { + outline-color: @theme_button_decoration_hover_breeze; + background-color: alpha(@theme_button_decoration_hover_breeze, 0.333); +} + +check:disabled, +radio:disabled { + background-color: alpha(@theme_base_color_breeze, 0.03); + outline-color: alpha(@theme_button_foreground_normal_breeze, 0.222); +} + +check:checked:disabled, +check:indeterminate:disabled, +radio:checked:disabled, +radio:indeterminate:disabled { + background-color: alpha(@theme_button_foreground_normal_breeze, 0.03); + outline-color: alpha(@theme_button_decoration_hover_breeze, 0.3); +} + +/* --- Switch --- */ + +switch { + outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.222); + outline-offset: -1px; + border-radius: 12px; + background-color: alpha(@theme_button_foreground_normal_breeze, 0.05); + color: transparent; +} + +switch:checked { + background: alpha(@theme_button_decoration_hover_breeze, 0.333); + outline-color: @theme_button_decoration_hover_breeze; +} + +switch:disabled { + background-color: alpha(@theme_button_foreground_normal_breeze, 0.03); +} + +switch:checked:disabled { + background: alpha(@theme_button_decoration_hover_breeze, 0.222); + outline-color: alpha(@theme_button_decoration_hover_breeze, 0.777); +} + +switch slider { + outline: 1px solid @borders_breeze; + outline-offset: -1px; + border-radius: 12px; + background: @theme_button_background_normal_breeze; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.125); +} + +switch:hover slider { + outline-color: @theme_button_decoration_hover_breeze; +} + +switch:focus slider { + outline-color: @theme_button_decoration_focus_breeze; +} + +switch:disabled slider { + box-shadow: none; + color: @theme_button_foreground_insensitive_breeze; + outline-color: @insensitive_borders_breeze; + background: @theme_button_background_insensitive_breeze; +} diff --git a/lact/Cargo.toml b/lact/Cargo.toml index 162a3af3..5e2a3071 100644 --- a/lact/Cargo.toml +++ b/lact/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [features] default = ["lact-gui", "nvidia"] -adw = ["lact-gui/adw"] nvidia = ["lact-daemon/nvidia"] [dependencies] diff --git a/pkg/recipes/lact-headless/recipe.yml b/pkg/recipes/lact-headless/recipe.yml index ca0647a6..923cecc4 100644 --- a/pkg/recipes/lact-headless/recipe.yml +++ b/pkg/recipes/lact-headless/recipe.yml @@ -9,7 +9,7 @@ metadata: source: - '../../../../LACT' provides: [ lact ] - conflicts: [ lact, lact-libadwaita ] + conflicts: [ lact ] depends: all: [ hwdata, vulkan-tools, clinfo ] debian-13+ubuntu-2404: [ libdrm-amdgpu1, libdrm2 ] diff --git a/pkg/recipes/lact/recipe.yml b/pkg/recipes/lact/recipe.yml index 5f656b83..56642010 100644 --- a/pkg/recipes/lact/recipe.yml +++ b/pkg/recipes/lact/recipe.yml @@ -9,19 +9,19 @@ metadata: source: - '../../../../LACT' provides: [ lact ] - conflicts: [ lact-headless, lact-libadwaita ] + conflicts: [ lact-headless ] depends: all: [ hwdata, vulkan-tools, clinfo ] - debian-13+ubuntu-2404: [ libgtk-4-1, libdrm2, libdrm-amdgpu1 ] - fedora-42+fedora-43: [ gtk4, libdrm ] - arch: [ gtk4, ocl-icd ] - opensuse-tumbleweed: [ gtk4 ] + debian-13+ubuntu-2404: [ libgtk-4-1, libdrm2, libdrm-amdgpu1, libadwaita-1-0 ] + fedora-42+fedora-43: [ gtk4, libdrm, libadwaita ] + arch: [ gtk4, ocl-icd, libadwaita ] + opensuse-tumbleweed: [ gtk4, libadwaita-1-0 ] build_depends: all: [ curl, make, clang, git, vulkan-tools, clinfo ] - debian-13+ubuntu-2404: [ libgtk-4-dev, pkg-config, build-essential, libdrm-dev, dbus ] - fedora-42+fedora-43: [ gtk4-devel, gcc, libdrm-devel, dbus ] - arch: [ gtk4, dbus, ocl-icd ] - opensuse-tumbleweed: [ gtk4-devel, libdrm-devel ] + debian-13+ubuntu-2404: [ libgtk-4-dev, pkg-config, build-essential, libdrm-dev, dbus, libadwaita-1-dev ] + fedora-42+fedora-43: [ gtk4-devel, gcc, libdrm-devel, dbus, libadwaita-devel ] + arch: [ gtk4, dbus, ocl-icd, libadwaita ] + opensuse-tumbleweed: [ gtk4-devel, libdrm-devel, libadwaita-devel ] all_images: true env: RUSTUP_URL: https://sh.rustup.rs