2022-08-14 15:56:21 +01:00
|
|
|
use crate::config::BarPosition;
|
2022-08-15 21:11:00 +01:00
|
|
|
use gtk::gdk::Monitor;
|
2022-08-14 14:30:13 +01:00
|
|
|
use gtk::prelude::*;
|
2022-08-15 21:11:00 +01:00
|
|
|
use gtk::{Application, ApplicationWindow, Button, Orientation};
|
2022-08-14 14:30:13 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Popup {
|
|
|
|
pub window: ApplicationWindow,
|
|
|
|
pub container: gtk::Box,
|
2022-08-15 21:11:00 +01:00
|
|
|
monitor: Monitor,
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Popup {
|
2022-08-14 15:56:21 +01:00
|
|
|
pub fn new(
|
|
|
|
name: &str,
|
|
|
|
app: &Application,
|
2022-08-15 21:11:00 +01:00
|
|
|
monitor: &Monitor,
|
2022-08-14 15:56:21 +01:00
|
|
|
orientation: Orientation,
|
|
|
|
bar_position: &BarPosition,
|
|
|
|
) -> Self {
|
2022-08-14 14:30:13 +01:00
|
|
|
let win = ApplicationWindow::builder().application(app).build();
|
|
|
|
|
|
|
|
gtk_layer_shell::init_for_window(&win);
|
|
|
|
gtk_layer_shell::set_layer(&win, gtk_layer_shell::Layer::Overlay);
|
|
|
|
|
2022-08-14 15:56:21 +01:00
|
|
|
gtk_layer_shell::set_margin(
|
|
|
|
&win,
|
|
|
|
gtk_layer_shell::Edge::Top,
|
|
|
|
if bar_position == &BarPosition::Top {
|
|
|
|
5
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
},
|
|
|
|
);
|
|
|
|
gtk_layer_shell::set_margin(
|
|
|
|
&win,
|
|
|
|
gtk_layer_shell::Edge::Bottom,
|
|
|
|
if bar_position == &BarPosition::Bottom {
|
|
|
|
5
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
},
|
|
|
|
);
|
2022-08-14 14:30:13 +01:00
|
|
|
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Left, 0);
|
|
|
|
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Right, 0);
|
|
|
|
|
2022-08-14 15:56:21 +01:00
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
&win,
|
|
|
|
gtk_layer_shell::Edge::Top,
|
|
|
|
bar_position == &BarPosition::Top,
|
|
|
|
);
|
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
&win,
|
|
|
|
gtk_layer_shell::Edge::Bottom,
|
|
|
|
bar_position == &BarPosition::Bottom,
|
|
|
|
);
|
2022-08-14 14:30:13 +01:00
|
|
|
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Left, true);
|
|
|
|
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Right, false);
|
|
|
|
|
|
|
|
let content = gtk::Box::builder()
|
|
|
|
.orientation(orientation)
|
|
|
|
.spacing(0)
|
|
|
|
.hexpand(false)
|
|
|
|
.name(name)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
content.style_context().add_class("popup");
|
|
|
|
|
|
|
|
win.add(&content);
|
|
|
|
|
|
|
|
win.connect_leave_notify_event(|win, ev| {
|
2022-08-15 21:11:00 +01:00
|
|
|
const THRESHOLD: f64 = 3.0;
|
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
let (w, _h) = win.size();
|
|
|
|
let (x, y) = ev.position();
|
|
|
|
|
|
|
|
// some child widgets trigger this event
|
|
|
|
// so check we're actually outside the window
|
|
|
|
if x < THRESHOLD || y < THRESHOLD || x > f64::from(w) - THRESHOLD {
|
|
|
|
win.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
Inhibit(false)
|
|
|
|
});
|
|
|
|
|
|
|
|
Self {
|
|
|
|
window: win,
|
|
|
|
container: content,
|
2022-08-15 21:11:00 +01:00
|
|
|
monitor: monitor.clone(),
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Shows the popover
|
2022-08-15 21:11:00 +01:00
|
|
|
pub fn show(&self, button: &Button) {
|
2022-08-14 14:30:13 +01:00
|
|
|
self.window.show_all();
|
2022-08-15 21:11:00 +01:00
|
|
|
self.set_pos(button);
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Hides the popover
|
|
|
|
pub fn hide(&self) {
|
|
|
|
self.window.hide();
|
|
|
|
}
|
2022-08-15 21:11:00 +01:00
|
|
|
|
|
|
|
/// Sets the popover's X position relative to the left border of the screen
|
|
|
|
fn set_pos(&self, button: &Button) {
|
|
|
|
let widget_width = button.allocation().width();
|
|
|
|
let screen_width = self.monitor.workarea().width();
|
|
|
|
let popup_width = self.window.allocated_width();
|
|
|
|
|
|
|
|
let (widget_x, _) = button
|
|
|
|
.translate_coordinates(&button.toplevel().unwrap(), 0, 0)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let widget_center = f64::from(widget_x) + f64::from(widget_width) / 2.0;
|
|
|
|
|
|
|
|
let mut offset = (widget_center - (f64::from(popup_width) / 2.0)).round();
|
|
|
|
|
|
|
|
if offset < 5.0 {
|
|
|
|
offset = 5.0;
|
|
|
|
} else if offset > f64::from(screen_width - popup_width) - 5.0 {
|
|
|
|
offset = f64::from(screen_width - popup_width) - 5.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_layer_shell::set_margin(&self.window, gtk_layer_shell::Edge::Left, offset as i32);
|
|
|
|
}
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|