popup fixes and clock gets nicer popup

This commit is contained in:
2026-09-15 11:46:16 +01:00
parent fb6b03b369
commit ac70a9133a
7 changed files with 87 additions and 63 deletions
+44 -25
View File
@@ -5,12 +5,12 @@
//! then opens the popup there; the active module renders its content.
use iced::advanced::widget as advanced_widget;
use iced::widget::{column, mouse_area, text};
use iced::{Alignment, Element, Length, Rectangle, Task};
use iced::widget::{column, container, mouse_area, text};
use iced::{Alignment, Border, Element, Length, Padding, Rectangle, Task};
use iced_layershell::actions::IcedNewPopupSettings;
use iced_layershell::reexport::{PopupAnchor, PopupGravity};
use common::ModuleEffect;
use common::{pill, ModuleEffect, PopupSettings};
use crate::msg::popup_open;
use crate::{Bar, Message, Msg};
@@ -19,17 +19,17 @@ use crate::{Bar, Message, Msg};
const POPUP_W: u32 = 150;
const POPUP_H: u32 = 100;
/// Gap (logical px) between the bar's bottom edge and the popup.
const POPUP_GAP: i32 = 32;
// Gap (logical px) between the bar's bottom edge and the popup.
// const POPUP_GAP: i32 = 32;
/// Opens a popup for `module_id` below its laid-out `bounds`. Size comes
/// from the module's `popup_size()` (default: small menu).
pub fn open_popup(bar: &mut Bar, module_id: String, bounds: Rectangle) -> Task<Message> {
bar.active_popup = Some(module_id.clone());
pub fn open_popup(bar: &mut Bar, bounds: Rectangle, settings: PopupSettings) -> Task<Message> {
bar.active_popup = Some(settings.module_id.clone());
let (w, h) = bar
.modules
.get(module_id.as_str())
.get(settings.module_id.as_str())
.and_then(|m| m.popup_size())
.unwrap_or((POPUP_W, POPUP_H));
@@ -41,14 +41,14 @@ pub fn open_popup(bar: &mut Bar, module_id: String, bounds: Rectangle) -> Task<M
bounds.width.round() as i32,
bounds.height.round() as i32,
);
let anchor_rect = (bx, by, bw, bh + POPUP_GAP);
let settings = IcedNewPopupSettings::on_current_surface((w, h), anchor_rect)
let anchor_rect = (bx, by, bw, bh + settings.gap);
let settings_popup = IcedNewPopupSettings::on_current_surface((w, h), anchor_rect)
.anchor(PopupAnchor::Bottom)
.gravity(PopupGravity::Bottom);
let (id, task) = popup_open(settings);
let (id, task) = popup_open(settings_popup);
bar.popup_id = Some(id);
tracing::debug!(module = %module_id, ?id, size = ?(w, h), "popup opened");
tracing::debug!(module = %settings.module_id, ?id, size = ?(w, h), "popup opened");
task
}
@@ -64,8 +64,8 @@ pub fn close_popup(bar: &mut Bar) -> Task<Message> {
/// Runs a widget-tree [`Operation`] that captures the laid-out bounds of the
/// given element, then reports them via `BoundsFound` for the module.
pub fn capture_bounds(module_id: String, element_id: String) -> Task<Message> {
let target = iced::widget::Id::from(element_id);
pub fn capture_bounds(settings: PopupSettings) -> Task<Message> {
let target = iced::widget::Id::from(settings.element_id.clone());
struct FindBounds {
target: iced::widget::Id,
@@ -98,7 +98,9 @@ pub fn capture_bounds(module_id: String, element_id: String) -> Task<Message> {
target,
found: None,
})
.map(move |bounds| Message::Effect(ModuleEffect::BoundsFound(module_id.clone(), bounds)))
.map(move |bounds| -> Message {
Message::Effect(ModuleEffect::BoundsFound(bounds, settings.clone()))
})
}
/// Popup widget tree on its own LayerShell surface; the active module
@@ -116,15 +118,32 @@ pub fn view(bar: &Bar) -> Element<'_, Message> {
})
.unwrap_or_else(|| text("unknown module").into());
column![
text(format!("{} menu", module_id))
.size(14)
.width(Length::Fill)
.align_x(Alignment::Center),
content,
mouse_area(text("close").size(12))
.on_press(Message::Effect(ModuleEffect::ClosePopup(popup_id))),
]
.spacing(1)
container(
column![
text(format!("{} menu", module_id))
.size(14)
.width(Length::Fill)
.align_x(Alignment::Center),
content,
mouse_area(container(text("close").size(12)).style(pill))
.on_press(Message::Effect(ModuleEffect::ClosePopup(popup_id))),
]
.spacing(1),
)
.padding(Padding::from(4))
.style(|theme| container::Style {
text_color: None,
background: Some(
iced::Background::Color(theme.extended_palette().background.base.color)
.scale_alpha(0.4),
),
border: Border {
width: 3.0,
radius: 10.into(),
color: theme.extended_palette().secondary.strong.color,
},
snap: true,
..Default::default()
})
.into()
}
+6 -6
View File
@@ -78,18 +78,18 @@ fn route(bar: &mut Bar, wire: Wire) -> Task<Message> {
/// Runs an effect; may set up bar state for it (e.g. which popup is open).
fn handle_effect(bar: &mut Bar, effect: ModuleEffect) -> Task<Message> {
match effect {
ModuleEffect::RequestPopup(module_id, element_id) => {
ModuleEffect::RequestPopup(settings) => {
// Toggle: close if already open for this module, else open.
if bar.active_popup.as_deref() == Some(module_id.as_str()) {
tracing::debug!(module = %module_id, "closing popup");
if bar.active_popup.as_deref() == Some(settings.module_id.as_str()) {
tracing::debug!(module = settings.module_id, "closing popup");
popup::close_popup(bar)
} else {
tracing::debug!(module = %module_id, "opening popup");
popup::capture_bounds(module_id, element_id)
tracing::debug!(module = settings.module_id, "opening popup");
popup::capture_bounds(settings)
}
}
ModuleEffect::BoundsFound(module_id, bounds) => popup::open_popup(bar, module_id, bounds),
ModuleEffect::BoundsFound(bounds, settings) => popup::open_popup(bar, bounds, settings),
ModuleEffect::ClosePopup(id) => {
// Request removal only; keep popup state so the popup content