Daylight bar chrome + embedded launcher, v0.7.5 pins #5

Merged
Breadway merged 41 commits from feature/theme-spotlight into main 2026-08-31 18:14:19 +08:00
Showing only changes of commit c68ed0d7e9 - Show all commits

View file

@ -5,18 +5,31 @@
//! *below* the exclusive zone, and Hyprland slides `breadbar-panel` in from
//! the right.
use std::cell::RefCell;
use std::rc::Rc;
use gtk4::gdk::Key;
use gtk4::prelude::*;
use gtk4_layer_shell::{KeyboardMode, LayerShell};
use gtk4_layer_shell::{Edge, KeyboardMode, LayerShell};
use crate::{bind_layer_monitor, theme};
/// A boxed, ref-counted, optionally-unset click-away callback — see
/// `PanelSet::on_dismiss`'s own doc comment.
type DismissCallback = Rc<RefCell<Option<Rc<dyn Fn()>>>>;
#[derive(Clone)]
pub struct PanelSet {
pub connectivity: gtk4::Window,
pub control: gtk4::Window,
pub media: gtk4::Window,
dismiss: gtk4::Window,
// Theme 04/spotlight's capsule (plan §7 phase 6c): an extra click-away
// callback invoked alongside the popover-dismiss path below, so the
// SAME `breadbar-dismiss` surface/click-catcher also collapses the
// capsule's drawer — see `show_capsule_dismiss`/`hide_dismiss` and
// `set_on_dismiss`. `None` under every other theme (never set).
on_dismiss: DismissCallback,
}
impl PanelSet {
@ -36,6 +49,7 @@ impl PanelSet {
control,
media,
dismiss,
on_dismiss: Rc::new(RefCell::new(None)),
};
set.wire_dismiss();
set.wire_escape();
@ -52,6 +66,10 @@ impl PanelSet {
pub fn show(&self, which: &gtk4::Window) {
self.hide_panels();
// A prior capsule search (see `show_capsule_dismiss`) may have left
// the shared dismiss surface's top margin pushed down past its
// popover-shaped default — restore it before this popover uses it.
self.reset_dismiss_margin();
// Dismiss first so the panel maps above it (same Overlay layer).
self.dismiss.set_visible(true);
self.dismiss.present();
@ -70,12 +88,55 @@ impl PanelSet {
self.media.set_visible(false);
}
/// Theme 04/spotlight's capsule (plan §7 phase 6c): registers `cb` to
/// run whenever the shared dismiss surface is clicked, alongside the
/// popovers' own `hide_all`. `cb` is expected to no-op when the capsule
/// isn't actually open (matching `close_fn`'s own guard in main.rs), so
/// this firing on an ordinary popover click-away is harmless.
pub fn set_on_dismiss(&self, cb: impl Fn() + 'static) {
*self.on_dismiss.borrow_mut() = Some(Rc::new(cb));
}
/// Shows the dismiss scrim with its clickable region starting at
/// `top_margin` px from the screen top, rather than the theme's own
/// popover-shaped default. See the call site in main.rs's capsule
/// `open_fn` for why this needs to be at least the capsule's own row
/// height plus the drawer's maximum possible height: the dismiss
/// surface's layer (`overlay`) always renders above the bar's own
/// (`top`), so if its clickable region ever reached up into where the
/// drawer is actually drawn, it would swallow clicks meant for a
/// result row instead of forwarding them.
pub fn show_capsule_dismiss(&self, top_margin: i32) {
self.dismiss.set_margin(Edge::Top, top_margin);
self.dismiss.set_visible(true);
self.dismiss.present();
}
/// Hides the dismiss scrim and restores its margin to the theme's own
/// popover default, so a later popover `show()` isn't left with a
/// leftover capsule-sized gap.
pub fn hide_dismiss(&self) {
self.reset_dismiss_margin();
self.dismiss.set_visible(false);
}
fn reset_dismiss_margin(&self) {
let theme = theme::shell_theme();
if let Some(surf) = theme.surfaces().get("breadbar-dismiss") {
let top = surf.offset.first().copied().unwrap_or(0.0) as i32;
self.dismiss.set_margin(Edge::Top, top);
}
}
fn wire_dismiss(&self) {
let set = self.clone();
let click = gtk4::GestureClick::new();
click.set_button(0);
click.connect_pressed(move |_, _, _, _| {
set.hide_all();
if let Some(cb) = set.on_dismiss.borrow().as_ref() {
cb();
}
});
if let Some(child) = self.dismiss.child() {
child.add_controller(click);