breadhelp 0.2.0: live guided tour overlay replacing static onboarding
Replaces the old in-window onboarding wizard with a real screen-wide tour: dim + spotlight cutout around the actual on-screen component (breadbar, breadbox), floating callout teaching the shortcut, and event-driven confirmation via real Hyprland/breadd signals instead of click-through fakery.
This commit is contained in:
parent
fea8f83204
commit
29b2445573
20 changed files with 1077 additions and 298 deletions
92
src/ui/tour/mask.rs
Normal file
92
src/ui/tour/mask.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//! The spotlight: up to 4 `Layer::Overlay` strip windows (top/bottom/left/
|
||||
//! right) sized to leave a target's bounding box as a real gap with no
|
||||
//! surface over it at all — gtk4-layer-shell has no click-through/input-
|
||||
//! region API (confirmed in its own docs), so the only way to let pointer
|
||||
//! input reach the real UI underneath is to literally not cover it with
|
||||
//! anything. A `Target::None` step instead gets one full-screen dim window,
|
||||
//! since there's nothing to leave a gap around.
|
||||
|
||||
use gtk4::prelude::*;
|
||||
use gtk4::{Box as GBox, Window};
|
||||
use gtk4_layer_shell::{Edge, KeyboardMode, Layer, LayerShell};
|
||||
|
||||
use super::target::Rect;
|
||||
|
||||
fn new_mask_window(monitor: &gdk4::Monitor) -> Window {
|
||||
let window = Window::new();
|
||||
window.set_decorated(false);
|
||||
window.add_css_class("tour-window");
|
||||
window.init_layer_shell();
|
||||
window.set_layer(Layer::Overlay);
|
||||
window.set_keyboard_mode(KeyboardMode::None);
|
||||
window.set_monitor(Some(monitor));
|
||||
let dim = GBox::new(gtk4::Orientation::Vertical, 0);
|
||||
dim.add_css_class("tour-mask");
|
||||
dim.set_hexpand(true);
|
||||
dim.set_vexpand(true);
|
||||
window.set_child(Some(&dim));
|
||||
window
|
||||
}
|
||||
|
||||
/// One dim window covering the whole monitor — used for `Target::None` steps.
|
||||
pub fn full_screen(monitor: &gdk4::Monitor) -> Vec<Window> {
|
||||
let window = new_mask_window(monitor);
|
||||
for edge in [Edge::Top, Edge::Bottom, Edge::Left, Edge::Right] {
|
||||
window.set_anchor(edge, true);
|
||||
}
|
||||
window.present();
|
||||
vec![window]
|
||||
}
|
||||
|
||||
/// The 4-strip letterbox around `rect`, in monitor-local coordinates.
|
||||
/// `monitor_size` is `(width, height)` from `gdk4::Monitor::geometry()`.
|
||||
pub fn around(monitor: &gdk4::Monitor, rect: Rect, monitor_size: (i32, i32)) -> Vec<Window> {
|
||||
let (mon_w, mon_h) = monitor_size;
|
||||
let mut windows = Vec::new();
|
||||
|
||||
let top_h = rect.y;
|
||||
if top_h > 0 {
|
||||
let w = new_mask_window(monitor);
|
||||
w.set_anchor(Edge::Top, true);
|
||||
w.set_anchor(Edge::Left, true);
|
||||
w.set_anchor(Edge::Right, true);
|
||||
w.set_default_size(-1, top_h);
|
||||
w.present();
|
||||
windows.push(w);
|
||||
}
|
||||
|
||||
let bottom_h = mon_h - (rect.y + rect.h);
|
||||
if bottom_h > 0 {
|
||||
let w = new_mask_window(monitor);
|
||||
w.set_anchor(Edge::Bottom, true);
|
||||
w.set_anchor(Edge::Left, true);
|
||||
w.set_anchor(Edge::Right, true);
|
||||
w.set_default_size(-1, bottom_h);
|
||||
w.present();
|
||||
windows.push(w);
|
||||
}
|
||||
|
||||
let left_w = rect.x;
|
||||
if left_w > 0 {
|
||||
let w = new_mask_window(monitor);
|
||||
w.set_anchor(Edge::Left, true);
|
||||
w.set_anchor(Edge::Top, true);
|
||||
w.set_margin(Edge::Top, rect.y);
|
||||
w.set_default_size(left_w, rect.h);
|
||||
w.present();
|
||||
windows.push(w);
|
||||
}
|
||||
|
||||
let right_w = mon_w - (rect.x + rect.w);
|
||||
if right_w > 0 {
|
||||
let w = new_mask_window(monitor);
|
||||
w.set_anchor(Edge::Right, true);
|
||||
w.set_anchor(Edge::Top, true);
|
||||
w.set_margin(Edge::Top, rect.y);
|
||||
w.set_default_size(right_w, rect.h);
|
||||
w.present();
|
||||
windows.push(w);
|
||||
}
|
||||
|
||||
windows
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue