mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-07-03 19:51:03 +02:00
feat: more positioning options (#23)
* feat: more positioning options Can now display the bar on the left/right, and avoid anchoring to edges to centre the bar. BREAKING CHANGE: The `left` and `right` config options have been renamed to `start` and `end`
This commit is contained in:
parent
1b853bcb71
commit
06cfad62e2
14 changed files with 254 additions and 83 deletions
147
src/popup.rs
147
src/popup.rs
|
@ -4,7 +4,7 @@ use crate::config::BarPosition;
|
|||
use crate::modules::ModuleInfo;
|
||||
use gtk::gdk::Monitor;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{ApplicationWindow, Button};
|
||||
use gtk::{ApplicationWindow, Button, Orientation};
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -12,6 +12,7 @@ pub struct Popup {
|
|||
pub window: ApplicationWindow,
|
||||
pub cache: HashMap<usize, gtk::Box>,
|
||||
monitor: Monitor,
|
||||
pos: BarPosition,
|
||||
}
|
||||
|
||||
impl Popup {
|
||||
|
@ -20,6 +21,8 @@ impl Popup {
|
|||
/// and an empty `gtk::Box` container.
|
||||
pub fn new(module_info: &ModuleInfo) -> Self {
|
||||
let pos = module_info.bar_position;
|
||||
let orientation = pos.get_orientation();
|
||||
|
||||
let win = ApplicationWindow::builder()
|
||||
.application(module_info.app)
|
||||
.build();
|
||||
|
@ -30,34 +33,69 @@ impl Popup {
|
|||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Top,
|
||||
if pos == &BarPosition::Top { 5 } else { 0 },
|
||||
if pos == BarPosition::Top { 5 } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Bottom,
|
||||
if pos == &BarPosition::Bottom { 5 } else { 0 },
|
||||
if pos == BarPosition::Bottom { 5 } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Left,
|
||||
if pos == BarPosition::Left { 5 } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Right,
|
||||
if pos == BarPosition::Right { 5 } else { 0 },
|
||||
);
|
||||
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Left, 0);
|
||||
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Right, 0);
|
||||
|
||||
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Top, pos == &BarPosition::Top);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Top,
|
||||
pos == BarPosition::Top || orientation == Orientation::Vertical,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Bottom,
|
||||
pos == &BarPosition::Bottom,
|
||||
pos == BarPosition::Bottom,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Left,
|
||||
pos == BarPosition::Left || orientation == Orientation::Horizontal,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(
|
||||
&win,
|
||||
gtk_layer_shell::Edge::Right,
|
||||
pos == BarPosition::Right,
|
||||
);
|
||||
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Left, true);
|
||||
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Right, false);
|
||||
|
||||
win.connect_leave_notify_event(|win, ev| {
|
||||
win.connect_leave_notify_event(move |win, ev| {
|
||||
const THRESHOLD: f64 = 3.0;
|
||||
|
||||
let (w, _h) = win.size();
|
||||
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 {
|
||||
let hide = match pos {
|
||||
BarPosition::Top => {
|
||||
x < THRESHOLD || y > f64::from(h) - THRESHOLD || x > f64::from(w) - THRESHOLD
|
||||
}
|
||||
BarPosition::Bottom => {
|
||||
x < THRESHOLD || y < THRESHOLD || x > f64::from(w) - THRESHOLD
|
||||
}
|
||||
BarPosition::Left => {
|
||||
y < THRESHOLD || x > f64::from(w) - THRESHOLD || y > f64::from(h) - THRESHOLD
|
||||
}
|
||||
BarPosition::Right => {
|
||||
y < THRESHOLD || x < THRESHOLD || y > f64::from(h) - THRESHOLD
|
||||
}
|
||||
};
|
||||
|
||||
if hide {
|
||||
win.hide();
|
||||
}
|
||||
|
||||
|
@ -68,6 +106,7 @@ impl Popup {
|
|||
window: win,
|
||||
cache: HashMap::new(),
|
||||
monitor: module_info.monitor.clone(),
|
||||
pos,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,10 +131,10 @@ impl Popup {
|
|||
}
|
||||
}
|
||||
|
||||
/// Shows the popover
|
||||
pub fn show(&self, button_x: i32, button_width: i32) {
|
||||
/// Shows the popup
|
||||
pub fn show(&self, geometry: ButtonGeometry) {
|
||||
self.window.show_all();
|
||||
self.set_pos(button_x, button_width);
|
||||
self.set_pos(geometry);
|
||||
}
|
||||
|
||||
/// Hides the popover
|
||||
|
@ -108,34 +147,84 @@ impl Popup {
|
|||
self.window.is_visible()
|
||||
}
|
||||
|
||||
/// Sets the popover's X position relative to the left border of the screen
|
||||
fn set_pos(&self, button_x: i32, button_width: i32) {
|
||||
let screen_width = self.monitor.workarea().width();
|
||||
let (popup_width, _popup_height) = self.window.size();
|
||||
/// Sets the popup's X/Y position relative to the left or border of the screen
|
||||
/// (depending on orientation).
|
||||
fn set_pos(&self, geometry: ButtonGeometry) {
|
||||
let orientation = self.pos.get_orientation();
|
||||
|
||||
let widget_center = f64::from(button_x) + f64::from(button_width) / 2.0;
|
||||
let mon_workarea = self.monitor.workarea();
|
||||
let screen_size = if orientation == Orientation::Horizontal {
|
||||
mon_workarea.width()
|
||||
} else {
|
||||
mon_workarea.height()
|
||||
};
|
||||
|
||||
let mut offset = (widget_center - (f64::from(popup_width) / 2.0)).round();
|
||||
let (popup_width, popup_height) = self.window.size();
|
||||
let popup_size = if orientation == Orientation::Horizontal {
|
||||
popup_width
|
||||
} else {
|
||||
popup_height
|
||||
};
|
||||
|
||||
let widget_center = f64::from(geometry.position) + f64::from(geometry.size) / 2.0;
|
||||
|
||||
let bar_offset = (f64::from(screen_size) - f64::from(geometry.bar_size)) / 2.0;
|
||||
|
||||
let mut offset = bar_offset + (widget_center - (f64::from(popup_size) / 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;
|
||||
} else if offset > f64::from(screen_size - popup_size) - 5.0 {
|
||||
offset = f64::from(screen_size - popup_size) - 5.0;
|
||||
}
|
||||
|
||||
gtk_layer_shell::set_margin(&self.window, gtk_layer_shell::Edge::Left, offset as i32);
|
||||
let edge = if orientation == Orientation::Horizontal {
|
||||
gtk_layer_shell::Edge::Left
|
||||
} else {
|
||||
gtk_layer_shell::Edge::Top
|
||||
};
|
||||
|
||||
gtk_layer_shell::set_margin(&self.window, edge, offset as i32);
|
||||
}
|
||||
|
||||
/// Gets the absolute X position of the button
|
||||
/// and its width.
|
||||
pub fn button_pos(button: &Button) -> (i32, i32) {
|
||||
let button_width = button.allocation().width();
|
||||
/// and its width / height (depending on orientation).
|
||||
pub fn button_pos(button: &Button, orientation: Orientation) -> ButtonGeometry {
|
||||
let button_size = if orientation == Orientation::Horizontal {
|
||||
button.allocation().width()
|
||||
} else {
|
||||
button.allocation().height()
|
||||
};
|
||||
|
||||
let top_level = button.toplevel().expect("Failed to get top-level widget");
|
||||
let (button_x, _) = button
|
||||
|
||||
let bar_size = if orientation == Orientation::Horizontal {
|
||||
top_level.allocation().width()
|
||||
} else {
|
||||
top_level.allocation().height()
|
||||
};
|
||||
|
||||
let (button_x, button_y) = button
|
||||
.translate_coordinates(&top_level, 0, 0)
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
(button_x, button_width)
|
||||
let button_pos = if orientation == Orientation::Horizontal {
|
||||
button_x
|
||||
} else {
|
||||
button_y
|
||||
};
|
||||
|
||||
ButtonGeometry {
|
||||
position: button_pos,
|
||||
size: button_size,
|
||||
bar_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ButtonGeometry {
|
||||
position: i32,
|
||||
size: i32,
|
||||
bar_size: i32,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue