This commit is contained in:
2026-09-14 00:55:25 +01:00
parent ec43d7b57a
commit e8c0e79bae
17 changed files with 183 additions and 46 deletions
+2 -12
View File
@@ -2,9 +2,9 @@
//! something is muted — the signal the quickshell Audio widget gives.
use iced::widget::{container, row, space, text};
use iced::{border, Alignment, Element, Length, Task, Theme};
use iced::{Alignment, Element, Length, Task};
use common::{AudioNode, BarModule, ModuleEffect, PipewireMsg, PipewireState, Service, Wire};
use common::{pill, AudioNode, BarModule, ModuleEffect, PipewireMsg, PipewireState, Service, Wire};
/// Glyphs exactly as the Quickshell Audio widget draws them: the speaker is a
/// Material `md-volume` icon, the mic a Font Awesome one.
@@ -19,7 +19,6 @@ const MIC_MUTED: &str = "\u{f131}"; // fa-microphone_slash
/// given — if the bar ever leaves 20 px, scale the two sizes here.
const REF_SLOT_W: f32 = 24.0;
const REF_SPACING: f32 = 4.0;
const REF_RADIUS: f32 = 3.5;
/// The speaker is re-drawn in the mono face, whose ink is 1168/1496 the size
/// of the proportional face quickshell uses, so it is pre-compensated.
const REF_SINK_SIZE: f32 = 20.0 * 1496.0 / 1168.0;
@@ -95,12 +94,3 @@ fn glyph(node: AudioNode, on: &'static str, muted: &'static str) -> &'static str
on
}
}
/// The quickshell pill: rounded, a shade lighter than the bar behind it.
fn pill(theme: &Theme) -> container::Style {
container::Style {
background: Some(theme.extended_palette().background.weak.color.into()),
border: border::rounded(REF_RADIUS),
..container::Style::default()
}
}
+13 -3
View File
@@ -3,9 +3,11 @@
//! service to switch which kind it publishes; right-click opens a popup.
use iced::widget::{container, mouse_area, text};
use iced::{Element, Task};
use iced::{Element, Padding, Task};
use common::{BarModule, ClockKind, ClockMsg, ClockPayload, Endpoint, ModuleEffect, Service, Wire};
use common::{
pill, BarModule, ClockKind, ClockMsg, ClockPayload, Endpoint, ModuleEffect, Service, Wire,
};
use serde::Deserialize;
use toml::Table;
@@ -88,6 +90,12 @@ impl BarModule for Clock {
.on_press(Wire::module(me, self.id(), ClockMsg::ToggleSeconds))
.on_right_press(Wire::module(me, self.id(), ClockMsg::OpenPopup)),
)
.style(pill)
.padding(Padding {
right: 3.0,
left: 3.0,
..Default::default()
})
.id(iced::widget::Id::from(self.id()))
.into(),
}
@@ -96,7 +104,9 @@ impl BarModule for Clock {
fn update(&mut self, msg: Wire) -> Task<ModuleEffect> {
// The service publishes a raw `ClockPayload`; UI sends `ClockMsg`.
if let Some(payload) = msg.downcast::<ClockPayload>() {
self.value = payload.value.clone();
self.value = match payload {
ClockPayload::Mins(v) | ClockPayload::Seconds(v) => v.clone(),
};
return Task::none();
}
match msg.downcast::<ClockMsg>() {
+4 -1
View File
@@ -76,7 +76,10 @@ impl BarModule for WeatherModule {
}
// Clock tick from the datetime service: track the current hour.
if let Some(payload) = msg.downcast::<ClockPayload>() {
self.hour = payload.value.split(':').next().and_then(|h| h.parse().ok());
let value = match payload {
ClockPayload::Mins(v) | ClockPayload::Seconds(v) => v,
};
self.hour = value.split(':').next().and_then(|h| h.parse().ok());
self.refresh();
}
match msg.downcast::<WeatherKind>() {
+19 -15
View File
@@ -10,17 +10,18 @@ use std::collections::BTreeSet;
use common::{BarModule, HyprlandEvent, HyprlandMsg, ModuleEffect, Service, Wire};
use iced::border;
use iced::theme::palette;
use iced::widget::{container, row, space};
use iced::{window, Color, Element, Length, Task};
use iced::{window, Element, Length, Task, Theme};
use serde::Deserialize;
use toml::Table;
/// Focused workspace (gruvbox base10 / `Colors.primaryText`).
const ACTIVE: Color = Color::from_rgb(0.9216, 0.8588, 0.6980);
/// Workspace exists but is not focused (base06 / `Colors.textSecondary`).
const EXISTS: Color = Color::from_rgb(0.4863, 0.4353, 0.3922);
/// Workspace does not exist (base04 / `Colors.textDisabled`).
const ABSENT: Color = Color::from_rgb(0.3137, 0.2863, 0.2706);
/// How far each state's cube fades from the theme text colour toward the
/// theme background. Opaque (mixed, not alpha) so cubes stay solid over the
/// transparent bar instead of washing out.
const FADE_ACTIVE: f32 = 0.0;
const FADE_EXISTS: f32 = 0.55;
const FADE_ABSENT: f32 = 0.8;
/// Look of the workspace row, from `[modules.workspaces]`; every field
/// defaults to the value Quickshell's `Workspaces.qml` hardcodes, so an
@@ -81,21 +82,24 @@ impl Workspaces {
}
fn cube(&self, id: i32) -> Element<'_, Wire> {
let (color, scale) = if self.active == Some(id) {
(ACTIVE, self.cfg.scale_active)
let (fade, scale) = if self.active == Some(id) {
(FADE_ACTIVE, self.cfg.scale_active)
} else if self.existing.contains(&id) {
(EXISTS, self.cfg.scale_exists)
(FADE_EXISTS, self.cfg.scale_exists)
} else {
(ABSENT, self.cfg.scale_absent)
(FADE_ABSENT, self.cfg.scale_absent)
};
let radius = self.cfg.radius;
let bar = container(space())
.width(Length::Fixed(self.cfg.slot_w * scale))
.height(Length::Fixed(self.cfg.slot_h * scale))
.style(move |_| container::Style {
background: Some(color.into()),
border: border::rounded(radius),
..Default::default()
.style(move |theme: &Theme| {
let p = theme.palette();
container::Style {
background: Some(palette::mix(p.text, p.background, fade).into()),
border: border::rounded(radius),
..Default::default()
}
});
container(bar)
.center_x(Length::Fixed(self.cfg.slot_w))