mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-07-03 03:31:03 +02:00
feat(ipc): commands for opening/closing popups
Also includes some refactoring around related GTK helper code
This commit is contained in:
parent
c582bc3390
commit
b7ee794bfc
30 changed files with 747 additions and 345 deletions
|
@ -2,8 +2,9 @@ use crate::clients::clipboard::{self, ClipboardEvent};
|
|||
use crate::clients::wayland::{ClipboardItem, ClipboardValue};
|
||||
use crate::config::{CommonConfig, TruncateMode};
|
||||
use crate::image::new_icon_button;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::popup::Popup;
|
||||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
|
||||
};
|
||||
use crate::try_send;
|
||||
use gtk::gdk_pixbuf::Pixbuf;
|
||||
use gtk::gio::{Cancellable, MemoryInputStream};
|
||||
|
@ -124,25 +125,26 @@ impl Module<Button> for ClipboardModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> color_eyre::Result<ModuleWidget<Button>> {
|
||||
let position = info.bar_position;
|
||||
|
||||
) -> color_eyre::Result<ModuleParts<Button>> {
|
||||
let button = new_icon_button(&self.icon, info.icon_theme, self.icon_size);
|
||||
button.style_context().add_class("btn");
|
||||
|
||||
button.connect_clicked(move |button| {
|
||||
let pos = Popup::widget_geometry(button, position.get_orientation());
|
||||
try_send!(context.tx, ModuleUpdateEvent::TogglePopup(pos));
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
});
|
||||
|
||||
// we need to bind to the receiver as the channel does not open
|
||||
// until the popup is first opened.
|
||||
context.widget_rx.attach(None, |_| Continue(true));
|
||||
|
||||
Ok(ModuleWidget {
|
||||
widget: button,
|
||||
popup: self.into_popup(context.controller_tx, context.popup_rx, info),
|
||||
})
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
}
|
||||
|
||||
fn into_popup(
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::add_class;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::popup::Popup;
|
||||
use crate::{send_async, try_send};
|
||||
use std::env;
|
||||
|
||||
use chrono::{DateTime, Local, Locale};
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Align, Button, Calendar, Label, Orientation};
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
|
||||
};
|
||||
use crate::{send_async, try_send};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ClockModule {
|
||||
/// Date/time format string.
|
||||
|
@ -96,17 +99,16 @@ impl Module<Button> for ClockModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Button>> {
|
||||
) -> Result<ModuleParts<Button>> {
|
||||
let button = Button::new();
|
||||
let label = Label::new(None);
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
button.add(&label);
|
||||
|
||||
let orientation = info.bar_position.get_orientation();
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(Popup::widget_geometry(button, orientation))
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -119,12 +121,11 @@ impl Module<Button> for ClockModule {
|
|||
Continue(true)
|
||||
});
|
||||
|
||||
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleWidget {
|
||||
widget: button,
|
||||
popup,
|
||||
})
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
}
|
||||
|
||||
fn into_popup(
|
||||
|
@ -136,12 +137,12 @@ impl Module<Button> for ClockModule {
|
|||
let container = gtk::Box::new(Orientation::Vertical, 0);
|
||||
|
||||
let clock = Label::builder().halign(Align::Center).build();
|
||||
add_class(&clock, "calendar-clock");
|
||||
clock.add_class("calendar-clock");
|
||||
|
||||
container.add(&clock);
|
||||
|
||||
let calendar = Calendar::new();
|
||||
add_class(&calendar, "calendar");
|
||||
calendar.add_class("calendar");
|
||||
container.add(&calendar);
|
||||
|
||||
let format = self.format_popup;
|
||||
|
|
|
@ -27,7 +27,7 @@ impl CustomWidget for BoxWidget {
|
|||
|
||||
if let Some(widgets) = self.widgets {
|
||||
for widget in widgets {
|
||||
widget.widget.add_to(&container, context, widget.common);
|
||||
widget.widget.add_to(&container, &context, widget.common);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use super::{CustomWidget, CustomWidgetContext, ExecEvent};
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::popup::Popup;
|
||||
use crate::{build, try_send};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, Label};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::PopupButton;
|
||||
use crate::{build, try_send};
|
||||
|
||||
use super::{CustomWidget, CustomWidgetContext, ExecEvent};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ButtonWidget {
|
||||
name: Option<String>,
|
||||
|
@ -19,6 +21,7 @@ impl CustomWidget for ButtonWidget {
|
|||
|
||||
fn into_widget(self, context: CustomWidgetContext) -> Self::Widget {
|
||||
let button = build!(self, Self::Widget);
|
||||
context.popup_buttons.borrow_mut().push(button.clone());
|
||||
|
||||
if let Some(text) = self.label {
|
||||
let label = Label::new(None);
|
||||
|
@ -32,7 +35,6 @@ impl CustomWidget for ButtonWidget {
|
|||
}
|
||||
|
||||
if let Some(exec) = self.on_click {
|
||||
let bar_orientation = context.bar_orientation;
|
||||
let tx = context.tx.clone();
|
||||
|
||||
button.connect_clicked(move |button| {
|
||||
|
@ -41,7 +43,7 @@ impl CustomWidget for ButtonWidget {
|
|||
ExecEvent {
|
||||
cmd: exec.clone(),
|
||||
args: None,
|
||||
geometry: Popup::widget_geometry(button, bar_orientation),
|
||||
id: button.popup_id(),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use super::{CustomWidget, CustomWidgetContext};
|
||||
use crate::build;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::image::ImageProvider;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Image;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::build;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::image::ImageProvider;
|
||||
|
||||
use super::{CustomWidget, CustomWidgetContext};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ImageWidget {
|
||||
name: Option<String>,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use super::{CustomWidget, CustomWidgetContext};
|
||||
use crate::build;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Label;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::build;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
|
||||
use super::{CustomWidget, CustomWidgetContext};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct LabelWidget {
|
||||
name: Option<String>,
|
||||
|
|
|
@ -13,15 +13,16 @@ use crate::config::CommonConfig;
|
|||
use crate::modules::custom::button::ButtonWidget;
|
||||
use crate::modules::custom::progress::ProgressWidget;
|
||||
use crate::modules::{
|
||||
wrap_widget, Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext,
|
||||
wrap_widget, Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::popup::WidgetGeometry;
|
||||
use crate::script::Script;
|
||||
use crate::send_async;
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{IconTheme, Orientation};
|
||||
use gtk::{Button, IconTheme, Orientation};
|
||||
use serde::Deserialize;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::{debug, error};
|
||||
|
@ -56,11 +57,12 @@ pub enum Widget {
|
|||
Progress(ProgressWidget),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
struct CustomWidgetContext<'a> {
|
||||
tx: &'a Sender<ExecEvent>,
|
||||
bar_orientation: Orientation,
|
||||
icon_theme: &'a IconTheme,
|
||||
popup_buttons: Rc<RefCell<Vec<Button>>>,
|
||||
}
|
||||
|
||||
trait CustomWidget {
|
||||
|
@ -115,11 +117,11 @@ fn try_get_orientation(orientation: &str) -> Result<Orientation> {
|
|||
|
||||
impl Widget {
|
||||
/// Creates this widget and adds it to the parent container
|
||||
fn add_to(self, parent: >k::Box, context: CustomWidgetContext, common: CommonConfig) {
|
||||
fn add_to(self, parent: >k::Box, context: &CustomWidgetContext, common: CommonConfig) {
|
||||
macro_rules! create {
|
||||
($widget:expr) => {
|
||||
wrap_widget(
|
||||
&$widget.into_widget(context),
|
||||
&$widget.into_widget(context.clone()),
|
||||
common,
|
||||
context.bar_orientation,
|
||||
)
|
||||
|
@ -143,7 +145,7 @@ impl Widget {
|
|||
pub struct ExecEvent {
|
||||
cmd: String,
|
||||
args: Option<Vec<String>>,
|
||||
geometry: WidgetGeometry,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl Module<gtk::Box> for CustomModule {
|
||||
|
@ -173,9 +175,9 @@ impl Module<gtk::Box> for CustomModule {
|
|||
error!("{err:?}");
|
||||
}
|
||||
} else if event.cmd == "popup:toggle" {
|
||||
send_async!(tx, ModuleUpdateEvent::TogglePopup(event.geometry));
|
||||
send_async!(tx, ModuleUpdateEvent::TogglePopup(event.id));
|
||||
} else if event.cmd == "popup:open" {
|
||||
send_async!(tx, ModuleUpdateEvent::OpenPopup(event.geometry));
|
||||
send_async!(tx, ModuleUpdateEvent::OpenPopup(event.id));
|
||||
} else if event.cmd == "popup:close" {
|
||||
send_async!(tx, ModuleUpdateEvent::ClosePopup);
|
||||
} else {
|
||||
|
@ -191,25 +193,30 @@ impl Module<gtk::Box> for CustomModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<gtk::Box>> {
|
||||
) -> Result<ModuleParts<gtk::Box>> {
|
||||
let orientation = info.bar_position.get_orientation();
|
||||
let container = gtk::Box::builder().orientation(orientation).build();
|
||||
|
||||
let popup_buttons = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
let custom_context = CustomWidgetContext {
|
||||
tx: &context.controller_tx,
|
||||
bar_orientation: orientation,
|
||||
icon_theme: info.icon_theme,
|
||||
popup_buttons: popup_buttons.clone(),
|
||||
};
|
||||
|
||||
self.bar.clone().into_iter().for_each(|widget| {
|
||||
widget
|
||||
.widget
|
||||
.add_to(&container, custom_context, widget.common);
|
||||
.add_to(&container, &custom_context, widget.common);
|
||||
});
|
||||
|
||||
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts_owned(popup_buttons.take());
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup,
|
||||
})
|
||||
|
@ -231,12 +238,13 @@ impl Module<gtk::Box> for CustomModule {
|
|||
tx: &tx,
|
||||
bar_orientation: info.bar_position.get_orientation(),
|
||||
icon_theme: info.icon_theme,
|
||||
popup_buttons: Rc::new(RefCell::new(vec![])),
|
||||
};
|
||||
|
||||
for widget in popup {
|
||||
widget
|
||||
.widget
|
||||
.add_to(&container, custom_context, widget.common);
|
||||
.add_to(&container, &custom_context, widget.common);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext};
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send};
|
||||
use gtk::prelude::*;
|
||||
use gtk::ProgressBar;
|
||||
use serde::Deserialize;
|
||||
use tokio::spawn;
|
||||
use tracing::error;
|
||||
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send};
|
||||
|
||||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ProgressWidget {
|
||||
name: Option<String>,
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext, ExecEvent};
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::popup::Popup;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send, try_send};
|
||||
use std::cell::Cell;
|
||||
use std::ops::Neg;
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::Scale;
|
||||
use serde::Deserialize;
|
||||
use std::cell::Cell;
|
||||
use std::ops::Neg;
|
||||
use tokio::spawn;
|
||||
use tracing::error;
|
||||
|
||||
use crate::modules::custom::set_length;
|
||||
use crate::script::{OutputStream, Script, ScriptInput};
|
||||
use crate::{build, send, try_send};
|
||||
|
||||
use super::{try_get_orientation, CustomWidget, CustomWidgetContext, ExecEvent};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SliderWidget {
|
||||
name: Option<String>,
|
||||
|
@ -78,7 +80,7 @@ impl CustomWidget for SliderWidget {
|
|||
Inhibit(false)
|
||||
});
|
||||
|
||||
scale.connect_change_value(move |scale, _, val| {
|
||||
scale.connect_change_value(move |_, _, val| {
|
||||
// GTK will send values outside min/max range
|
||||
let val = val.clamp(min, max);
|
||||
|
||||
|
@ -88,7 +90,7 @@ impl CustomWidget for SliderWidget {
|
|||
ExecEvent {
|
||||
cmd: on_change.clone(),
|
||||
args: Some(vec![val.to_string()]),
|
||||
geometry: Popup::widget_geometry(scale, context.bar_orientation),
|
||||
id: usize::MAX // ignored
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::clients::wayland::{self, ToplevelEvent};
|
||||
use crate::config::{CommonConfig, TruncateMode};
|
||||
use crate::gtk_helpers::add_class;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::ImageProvider;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{lock, send_async, try_send};
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
|
@ -104,19 +104,19 @@ impl Module<gtk::Box> for FocusedModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<gtk::Box>> {
|
||||
) -> Result<ModuleParts<gtk::Box>> {
|
||||
let icon_theme = info.icon_theme;
|
||||
|
||||
let container = gtk::Box::new(info.bar_position.get_orientation(), 5);
|
||||
|
||||
let icon = gtk::Image::new();
|
||||
if self.show_icon {
|
||||
add_class(&icon, "icon");
|
||||
icon.add_class("icon");
|
||||
container.add(&icon);
|
||||
}
|
||||
|
||||
let label = Label::new(None);
|
||||
add_class(&label, "label");
|
||||
label.add_class("label");
|
||||
|
||||
if let Some(truncate) = self.truncate {
|
||||
truncate.truncate_label(&label);
|
||||
|
@ -144,7 +144,7 @@ impl Module<gtk::Box> for FocusedModule {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup: None,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::dynamic_value::dynamic_string;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::try_send;
|
||||
use color_eyre::Result;
|
||||
use glib::Continue;
|
||||
|
@ -52,7 +52,7 @@ impl Module<Label> for LabelModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Label>> {
|
||||
) -> Result<ModuleParts<Label>> {
|
||||
let label = Label::new(None);
|
||||
label.set_use_markup(true);
|
||||
|
||||
|
@ -64,7 +64,7 @@ impl Module<Label> for LabelModule {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: label,
|
||||
popup: None,
|
||||
})
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::open_state::OpenState;
|
||||
use crate::clients::wayland::ToplevelHandle;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::ImageProvider;
|
||||
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
|
||||
use crate::modules::ModuleUpdateEvent;
|
||||
use crate::popup::Popup;
|
||||
use crate::{read_lock, try_send};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
|
@ -249,7 +249,7 @@ impl ItemButton {
|
|||
|
||||
try_send!(
|
||||
tx,
|
||||
ModuleUpdateEvent::OpenPopup(Popup::widget_geometry(button, orientation))
|
||||
ModuleUpdateEvent::OpenPopupAt(button.geometry(orientation))
|
||||
);
|
||||
} else {
|
||||
try_send!(tx, ModuleUpdateEvent::ClosePopup);
|
||||
|
|
|
@ -7,7 +7,9 @@ use crate::clients::wayland::{self, ToplevelEvent};
|
|||
use crate::config::CommonConfig;
|
||||
use crate::desktop_file::find_desktop_file;
|
||||
use crate::modules::launcher::item::AppearanceOptions;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{arc_mut, lock, send_async, try_send, write_lock};
|
||||
use color_eyre::{Help, Report};
|
||||
use glib::Continue;
|
||||
|
@ -313,7 +315,7 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> crate::Result<ModuleWidget<gtk::Box>> {
|
||||
) -> crate::Result<ModuleParts<gtk::Box>> {
|
||||
let icon_theme = info.icon_theme;
|
||||
|
||||
let container = gtk::Box::new(info.bar_position.get_orientation(), 0);
|
||||
|
@ -408,8 +410,11 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
});
|
||||
}
|
||||
|
||||
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
||||
Ok(ModuleWidget {
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts(vec![]); // since item buttons are dynamic, they pass their geometry directly
|
||||
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup,
|
||||
})
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use color_eyre::Result;
|
||||
use glib::IsA;
|
||||
use gtk::gdk::{EventMask, Monitor};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Application, Button, EventBox, IconTheme, Orientation, Revealer, Widget};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::bridge_channel::BridgeChannel;
|
||||
use crate::config::{BarPosition, CommonConfig, TransitionType};
|
||||
use crate::gtk_helpers::{IronbarGtkExt, WidgetGeometry};
|
||||
use crate::popup::Popup;
|
||||
use crate::{send, write_lock};
|
||||
|
||||
#[cfg(feature = "clipboard")]
|
||||
pub mod clipboard;
|
||||
/// Displays the current date and time.
|
||||
|
@ -24,19 +40,6 @@ pub mod upower;
|
|||
#[cfg(feature = "workspaces")]
|
||||
pub mod workspaces;
|
||||
|
||||
use crate::bridge_channel::BridgeChannel;
|
||||
use crate::config::{BarPosition, CommonConfig, TransitionType};
|
||||
use crate::popup::{Popup, WidgetGeometry};
|
||||
use crate::{read_lock, send, write_lock};
|
||||
use color_eyre::Result;
|
||||
use glib::IsA;
|
||||
use gtk::gdk::{EventMask, Monitor};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Application, EventBox, IconTheme, Orientation, Revealer, Widget};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ModuleLocation {
|
||||
Left,
|
||||
|
@ -54,13 +57,15 @@ pub struct ModuleInfo<'a> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum ModuleUpdateEvent<T> {
|
||||
/// Sends an update to the module UI
|
||||
/// Sends an update to the module UI.
|
||||
Update(T),
|
||||
/// Toggles the open state of the popup.
|
||||
TogglePopup(WidgetGeometry),
|
||||
/// Takes the button ID.
|
||||
TogglePopup(usize),
|
||||
/// Force sets the popup open.
|
||||
/// Takes the button X position and width.
|
||||
OpenPopup(WidgetGeometry),
|
||||
/// Takes the button ID.
|
||||
OpenPopup(usize),
|
||||
OpenPopupAt(WidgetGeometry),
|
||||
/// Force sets the popup closed.
|
||||
ClosePopup,
|
||||
}
|
||||
|
@ -73,9 +78,55 @@ pub struct WidgetContext<TSend, TReceive> {
|
|||
pub popup_rx: glib::Receiver<TSend>,
|
||||
}
|
||||
|
||||
pub struct ModuleWidget<W: IsA<Widget>> {
|
||||
pub struct ModuleParts<W: IsA<Widget>> {
|
||||
pub widget: W,
|
||||
pub popup: Option<gtk::Box>,
|
||||
pub popup: Option<ModulePopupParts>,
|
||||
}
|
||||
|
||||
impl<W: IsA<Widget>> ModuleParts<W> {
|
||||
fn new(widget: W, popup: Option<ModulePopupParts>) -> Self {
|
||||
Self { widget, popup }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ModulePopupParts {
|
||||
/// The popup container, with all its contents
|
||||
pub container: gtk::Box,
|
||||
/// An array of buttons which can be used for opening the popup.
|
||||
/// For most modules, this will only be a single button.
|
||||
/// For some advanced modules, such as `Launcher`, this is all item buttons.
|
||||
pub buttons: Vec<Button>,
|
||||
}
|
||||
|
||||
pub trait ModulePopup {
|
||||
fn into_popup_parts(self, buttons: Vec<&Button>) -> Option<ModulePopupParts>;
|
||||
fn into_popup_parts_owned(self, buttons: Vec<Button>) -> Option<ModulePopupParts>;
|
||||
}
|
||||
|
||||
impl ModulePopup for Option<gtk::Box> {
|
||||
fn into_popup_parts(self, buttons: Vec<&Button>) -> Option<ModulePopupParts> {
|
||||
self.into_popup_parts_owned(buttons.into_iter().cloned().collect())
|
||||
}
|
||||
|
||||
fn into_popup_parts_owned(self, buttons: Vec<Button>) -> Option<ModulePopupParts> {
|
||||
self.map(|container| ModulePopupParts { container, buttons })
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PopupButton {
|
||||
fn popup_id(&self) -> usize;
|
||||
}
|
||||
|
||||
impl PopupButton for Button {
|
||||
/// Gets the popup ID associated with this button.
|
||||
/// This should only be called on buttons which are known to be associated with popups.
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if an ID has not been set.
|
||||
fn popup_id(&self) -> usize {
|
||||
*self.get_tag("popup-id").expect("data to exist")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Module<W>
|
||||
|
@ -98,7 +149,7 @@ where
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<W>>;
|
||||
) -> Result<ModuleParts<W>>;
|
||||
|
||||
fn into_popup(
|
||||
self,
|
||||
|
@ -118,9 +169,10 @@ where
|
|||
pub fn create_module<TModule, TWidget, TSend, TRec>(
|
||||
module: TModule,
|
||||
id: usize,
|
||||
name: Option<String>,
|
||||
info: &ModuleInfo,
|
||||
popup: &Arc<RwLock<Popup>>,
|
||||
) -> Result<ModuleWidget<TWidget>>
|
||||
) -> Result<ModuleParts<TWidget>>
|
||||
where
|
||||
TModule: Module<TWidget, SendMessage = TSend, ReceiveMessage = TRec>,
|
||||
TWidget: IsA<Widget>,
|
||||
|
@ -142,29 +194,45 @@ where
|
|||
controller_tx: ui_tx,
|
||||
};
|
||||
|
||||
let name = TModule::name();
|
||||
let module_name = TModule::name();
|
||||
let instance_name = name.unwrap_or_else(|| module_name.to_string());
|
||||
|
||||
let module_parts = module.into_widget(context, info)?;
|
||||
module_parts.widget.style_context().add_class(name);
|
||||
module_parts.widget.style_context().add_class(module_name);
|
||||
|
||||
let mut has_popup = false;
|
||||
if let Some(popup_content) = module_parts.popup.clone() {
|
||||
let has_popup = if let Some(popup_content) = module_parts.popup.clone() {
|
||||
popup_content
|
||||
.container
|
||||
.style_context()
|
||||
.add_class(&format!("popup-{name}"));
|
||||
.add_class(&format!("popup-{module_name}"));
|
||||
|
||||
register_popup_content(popup, id, popup_content);
|
||||
has_popup = true;
|
||||
}
|
||||
register_popup_content(popup, id, instance_name, popup_content);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
setup_receiver(channel, w_tx, p_tx, popup.clone(), name, id, has_popup);
|
||||
setup_receiver(
|
||||
channel,
|
||||
w_tx,
|
||||
p_tx,
|
||||
popup.clone(),
|
||||
module_name,
|
||||
id,
|
||||
has_popup,
|
||||
);
|
||||
|
||||
Ok(module_parts)
|
||||
}
|
||||
|
||||
/// Registers the popup content with the popup.
|
||||
fn register_popup_content(popup: &Arc<RwLock<Popup>>, id: usize, popup_content: gtk::Box) {
|
||||
write_lock!(popup).register_content(id, popup_content);
|
||||
fn register_popup_content(
|
||||
popup: &Arc<RwLock<Popup>>,
|
||||
id: usize,
|
||||
name: String,
|
||||
popup_content: ModulePopupParts,
|
||||
) {
|
||||
write_lock!(popup).register_content(id, name, popup_content);
|
||||
}
|
||||
|
||||
/// Sets up the bridge channel receiver
|
||||
|
@ -196,40 +264,51 @@ fn setup_receiver<TSend>(
|
|||
|
||||
send!(w_tx, update);
|
||||
}
|
||||
ModuleUpdateEvent::TogglePopup(geometry) => {
|
||||
ModuleUpdateEvent::TogglePopup(button_id) => {
|
||||
debug!("Toggling popup for {} [#{}]", name, id);
|
||||
let popup = read_lock!(popup);
|
||||
let mut popup = write_lock!(popup);
|
||||
if popup.is_visible() {
|
||||
popup.hide();
|
||||
} else {
|
||||
popup.show_content(id);
|
||||
popup.show(geometry);
|
||||
popup.show(id, button_id);
|
||||
|
||||
// force re-render on initial open to try and fix size issue
|
||||
if !has_popup_opened {
|
||||
popup.show_content(id);
|
||||
popup.show(geometry);
|
||||
popup.show(id, button_id);
|
||||
has_popup_opened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ModuleUpdateEvent::OpenPopup(geometry) => {
|
||||
ModuleUpdateEvent::OpenPopup(button_id) => {
|
||||
debug!("Opening popup for {} [#{}]", name, id);
|
||||
|
||||
let popup = read_lock!(popup);
|
||||
let mut popup = write_lock!(popup);
|
||||
popup.hide();
|
||||
popup.show_content(id);
|
||||
popup.show(geometry);
|
||||
popup.show(id, button_id);
|
||||
|
||||
// force re-render on initial open to try and fix size issue
|
||||
if !has_popup_opened {
|
||||
popup.show_content(id);
|
||||
popup.show(geometry);
|
||||
popup.show(id, button_id);
|
||||
has_popup_opened = true;
|
||||
}
|
||||
}
|
||||
ModuleUpdateEvent::OpenPopupAt(geometry) => {
|
||||
debug!("Opening popup for {} [#{}]", name, id);
|
||||
|
||||
let mut popup = write_lock!(popup);
|
||||
popup.hide();
|
||||
popup.show_at(id, geometry);
|
||||
|
||||
// force re-render on initial open to try and fix size issue
|
||||
if !has_popup_opened {
|
||||
popup.show_at(id, geometry);
|
||||
has_popup_opened = true;
|
||||
}
|
||||
}
|
||||
ModuleUpdateEvent::ClosePopup => {
|
||||
debug!("Closing popup for {} [#{}]", name, id);
|
||||
|
||||
let popup = read_lock!(popup);
|
||||
let mut popup = write_lock!(popup);
|
||||
popup.hide();
|
||||
}
|
||||
}
|
||||
|
@ -239,14 +318,14 @@ fn setup_receiver<TSend>(
|
|||
}
|
||||
|
||||
pub fn set_widget_identifiers<TWidget: IsA<Widget>>(
|
||||
widget_parts: &ModuleWidget<TWidget>,
|
||||
widget_parts: &ModuleParts<TWidget>,
|
||||
common: &CommonConfig,
|
||||
) {
|
||||
if let Some(ref name) = common.name {
|
||||
widget_parts.widget.set_widget_name(name);
|
||||
|
||||
if let Some(ref popup) = widget_parts.popup {
|
||||
popup.set_widget_name(&format!("popup-{name}"));
|
||||
popup.container.set_widget_name(&format!("popup-{name}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +337,10 @@ pub fn set_widget_identifiers<TWidget: IsA<Widget>>(
|
|||
|
||||
if let Some(ref popup) = widget_parts.popup {
|
||||
for part in class.split(' ') {
|
||||
popup.style_context().add_class(&format!("popup-{part}"));
|
||||
popup
|
||||
.container
|
||||
.style_context()
|
||||
.add_class(&format!("popup-{part}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
mod config;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::clients::music::{
|
||||
self, MusicClient, PlayerState, PlayerUpdate, ProgressTick, Status, Track,
|
||||
};
|
||||
use crate::gtk_helpers::add_class;
|
||||
use crate::image::{new_icon_button, new_icon_label, ImageProvider};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::popup::Popup;
|
||||
use crate::{send_async, try_send};
|
||||
use color_eyre::Result;
|
||||
use glib::{Continue, PropertySet};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme, Label, Orientation, Scale};
|
||||
use regex::Regex;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::error;
|
||||
|
||||
use crate::clients::music::{
|
||||
self, MusicClient, PlayerState, PlayerUpdate, ProgressTick, Status, Track,
|
||||
};
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::{new_icon_button, new_icon_label, ImageProvider};
|
||||
use crate::modules::PopupButton;
|
||||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{send_async, try_send};
|
||||
|
||||
pub use self::config::MusicModule;
|
||||
use self::config::PlayerType;
|
||||
|
||||
mod config;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PlayerCommand {
|
||||
Previous,
|
||||
|
@ -178,10 +182,10 @@ impl Module<Button> for MusicModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Button>> {
|
||||
) -> Result<ModuleParts<Button>> {
|
||||
let button = Button::new();
|
||||
let button_contents = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
add_class(&button_contents, "contents");
|
||||
button_contents.add_class("contents");
|
||||
|
||||
button.add(&button_contents);
|
||||
|
||||
|
@ -199,16 +203,11 @@ impl Module<Button> for MusicModule {
|
|||
button_contents.add(&icon_play);
|
||||
button_contents.add(&label);
|
||||
|
||||
let orientation = info.bar_position.get_orientation();
|
||||
|
||||
{
|
||||
let tx = context.tx.clone();
|
||||
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
tx,
|
||||
ModuleUpdateEvent::TogglePopup(Popup::widget_geometry(button, orientation,))
|
||||
);
|
||||
try_send!(tx, ModuleUpdateEvent::TogglePopup(button.popup_id()));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -252,12 +251,11 @@ impl Module<Button> for MusicModule {
|
|||
});
|
||||
};
|
||||
|
||||
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleWidget {
|
||||
widget: button,
|
||||
popup,
|
||||
})
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
}
|
||||
|
||||
fn into_popup(
|
||||
|
@ -275,7 +273,7 @@ impl Module<Button> for MusicModule {
|
|||
.width_request(128)
|
||||
.height_request(128)
|
||||
.build();
|
||||
add_class(&album_image, "album-art");
|
||||
album_image.add_class("album-art");
|
||||
|
||||
let icons = self.icons;
|
||||
|
||||
|
@ -284,28 +282,28 @@ impl Module<Button> for MusicModule {
|
|||
let album_label = IconLabel::new(&icons.album, None, icon_theme);
|
||||
let artist_label = IconLabel::new(&icons.artist, None, icon_theme);
|
||||
|
||||
add_class(&title_label.container, "title");
|
||||
add_class(&album_label.container, "album");
|
||||
add_class(&artist_label.container, "artist");
|
||||
title_label.container.add_class("title");
|
||||
album_label.container.add_class("album");
|
||||
artist_label.container.add_class("artist");
|
||||
|
||||
info_box.add(&title_label.container);
|
||||
info_box.add(&album_label.container);
|
||||
info_box.add(&artist_label.container);
|
||||
|
||||
let controls_box = gtk::Box::new(Orientation::Horizontal, 0);
|
||||
add_class(&controls_box, "controls");
|
||||
controls_box.add_class("controls");
|
||||
|
||||
let btn_prev = new_icon_button(&icons.prev, icon_theme, self.icon_size);
|
||||
add_class(&btn_prev, "btn-prev");
|
||||
btn_prev.add_class("btn-prev");
|
||||
|
||||
let btn_play = new_icon_button(&icons.play, icon_theme, self.icon_size);
|
||||
add_class(&btn_play, "btn-play");
|
||||
btn_play.add_class("btn-play");
|
||||
|
||||
let btn_pause = new_icon_button(&icons.pause, icon_theme, self.icon_size);
|
||||
add_class(&btn_pause, "btn-pause");
|
||||
btn_pause.add_class("btn-pause");
|
||||
|
||||
let btn_next = new_icon_button(&icons.next, icon_theme, self.icon_size);
|
||||
add_class(&btn_next, "btn-next");
|
||||
btn_next.add_class("btn-next");
|
||||
|
||||
controls_box.add(&btn_prev);
|
||||
controls_box.add(&btn_play);
|
||||
|
@ -315,14 +313,14 @@ impl Module<Button> for MusicModule {
|
|||
info_box.add(&controls_box);
|
||||
|
||||
let volume_box = gtk::Box::new(Orientation::Vertical, 5);
|
||||
add_class(&volume_box, "volume");
|
||||
volume_box.add_class("volume");
|
||||
|
||||
let volume_slider = Scale::with_range(Orientation::Vertical, 0.0, 100.0, 5.0);
|
||||
volume_slider.set_inverted(true);
|
||||
add_class(&volume_slider, "slider");
|
||||
volume_slider.add_class("slider");
|
||||
|
||||
let volume_icon = new_icon_label(&icons.volume, icon_theme, self.icon_size);
|
||||
add_class(&volume_icon, "icon");
|
||||
volume_icon.add_class("icon");
|
||||
|
||||
volume_box.pack_start(&volume_slider, true, true, 0);
|
||||
volume_box.pack_end(&volume_icon, false, false, 0);
|
||||
|
@ -359,17 +357,17 @@ impl Module<Button> for MusicModule {
|
|||
});
|
||||
|
||||
let progress_box = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
add_class(&progress_box, "progress");
|
||||
progress_box.add_class("progress");
|
||||
|
||||
let progress_label = Label::new(None);
|
||||
add_class(&progress_label, "label");
|
||||
progress_label.add_class("label");
|
||||
|
||||
let progress = Scale::builder()
|
||||
.orientation(Orientation::Horizontal)
|
||||
.draw_value(false)
|
||||
.hexpand(true)
|
||||
.build();
|
||||
add_class(&progress, "slider");
|
||||
progress.add_class("slider");
|
||||
|
||||
progress_box.add(&progress);
|
||||
progress_box.add(&progress_label);
|
||||
|
@ -546,8 +544,8 @@ impl IconLabel {
|
|||
let icon = new_icon_label(icon_input, icon_theme, 24);
|
||||
let label = Label::new(label);
|
||||
|
||||
add_class(&icon, "icon-box");
|
||||
add_class(&label, "label");
|
||||
icon.add_class("icon-box");
|
||||
label.add_class("label");
|
||||
|
||||
container.add(&icon);
|
||||
container.add(&label);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::script::{OutputStream, Script, ScriptMode};
|
||||
use crate::try_send;
|
||||
use color_eyre::{Help, Report, Result};
|
||||
|
@ -83,7 +83,7 @@ impl Module<Label> for ScriptModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Label>> {
|
||||
) -> Result<ModuleParts<Label>> {
|
||||
let label = Label::builder().use_markup(true).build();
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
|
||||
|
@ -95,7 +95,7 @@ impl Module<Label> for ScriptModule {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: label,
|
||||
popup: None,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::add_class;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::send_async;
|
||||
use color_eyre::Result;
|
||||
use gtk::prelude::*;
|
||||
|
@ -186,7 +186,7 @@ impl Module<gtk::Box> for SysInfoModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<gtk::Box>> {
|
||||
) -> Result<ModuleParts<gtk::Box>> {
|
||||
let re = Regex::new(r"\{([^}]+)}")?;
|
||||
|
||||
let container = gtk::Box::new(info.bar_position.get_orientation(), 10);
|
||||
|
@ -196,7 +196,7 @@ impl Module<gtk::Box> for SysInfoModule {
|
|||
for format in &self.format {
|
||||
let label = Label::builder().label(format).use_markup(true).build();
|
||||
|
||||
add_class(&label, "item");
|
||||
label.add_class("item");
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
|
||||
container.add(&label);
|
||||
|
@ -220,7 +220,7 @@ impl Module<gtk::Box> for SysInfoModule {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup: None,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::clients::system_tray::get_tray_event_client;
|
||||
use crate::config::CommonConfig;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{await_sync, try_send};
|
||||
use color_eyre::Result;
|
||||
use gtk::gdk_pixbuf::{Colorspace, InterpType};
|
||||
|
@ -172,7 +172,7 @@ impl Module<MenuBar> for TrayModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
_info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<MenuBar>> {
|
||||
) -> Result<ModuleParts<MenuBar>> {
|
||||
let container = MenuBar::new();
|
||||
|
||||
{
|
||||
|
@ -238,7 +238,7 @@ impl Module<MenuBar> for TrayModule {
|
|||
});
|
||||
};
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup: None,
|
||||
})
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
use crate::clients::upower::get_display_proxy;
|
||||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::add_class;
|
||||
use crate::image::ImageProvider;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::popup::Popup;
|
||||
use crate::{await_sync, error, send_async, try_send};
|
||||
use color_eyre::Result;
|
||||
use futures_lite::stream::StreamExt;
|
||||
use gtk::{prelude::*, Button};
|
||||
|
@ -15,6 +8,16 @@ use tokio::sync::mpsc::{Receiver, Sender};
|
|||
use upower_dbus::BatteryState;
|
||||
use zbus;
|
||||
|
||||
use crate::clients::upower::get_display_proxy;
|
||||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::ImageProvider;
|
||||
use crate::modules::PopupButton;
|
||||
use crate::modules::{
|
||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext,
|
||||
};
|
||||
use crate::{await_sync, error, send_async, try_send};
|
||||
|
||||
const DAY: i64 = 24 * 60 * 60;
|
||||
const HOUR: i64 = 60 * 60;
|
||||
const MINUTE: i64 = 60;
|
||||
|
@ -150,32 +153,31 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Button>> {
|
||||
) -> Result<ModuleParts<Button>> {
|
||||
let icon_theme = info.icon_theme.clone();
|
||||
let icon = gtk::Image::new();
|
||||
add_class(&icon, "icon");
|
||||
icon.add_class("icon");
|
||||
|
||||
let label = Label::builder()
|
||||
.label(&self.format)
|
||||
.use_markup(true)
|
||||
.build();
|
||||
add_class(&label, "label");
|
||||
label.add_class("label");
|
||||
|
||||
let container = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
add_class(&container, "contents");
|
||||
container.add_class("contents");
|
||||
|
||||
let button = Button::new();
|
||||
add_class(&button, "button");
|
||||
button.add_class("button");
|
||||
|
||||
container.add(&icon);
|
||||
container.add(&label);
|
||||
button.add(&container);
|
||||
|
||||
let orientation = info.bar_position.get_orientation();
|
||||
button.connect_clicked(move |button| {
|
||||
try_send!(
|
||||
context.tx,
|
||||
ModuleUpdateEvent::TogglePopup(Popup::widget_geometry(button, orientation))
|
||||
ModuleUpdateEvent::TogglePopup(button.popup_id())
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -193,12 +195,11 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
Continue(true)
|
||||
});
|
||||
|
||||
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
||||
let popup = self
|
||||
.into_popup(context.controller_tx, context.popup_rx, info)
|
||||
.into_popup_parts(vec![&button]);
|
||||
|
||||
Ok(ModuleWidget {
|
||||
widget: button,
|
||||
popup,
|
||||
})
|
||||
Ok(ModuleParts::new(button, popup))
|
||||
}
|
||||
|
||||
fn into_popup(
|
||||
|
@ -215,7 +216,7 @@ impl Module<gtk::Button> for UpowerModule {
|
|||
.build();
|
||||
|
||||
let label = Label::new(None);
|
||||
add_class(&label, "upower-details");
|
||||
label.add_class("upower-details");
|
||||
container.add(&label);
|
||||
|
||||
rx.attach(None, move |properties| {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::clients::compositor::{Compositor, WorkspaceUpdate};
|
||||
use crate::config::CommonConfig;
|
||||
use crate::image::new_icon_button;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{send_async, try_send};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
|
@ -154,7 +154,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
self,
|
||||
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
||||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<gtk::Box>> {
|
||||
) -> Result<ModuleParts<gtk::Box>> {
|
||||
let container = gtk::Box::new(info.bar_position.get_orientation(), 0);
|
||||
|
||||
let name_map = self.name_map.unwrap_or_default();
|
||||
|
@ -277,7 +277,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(ModuleWidget {
|
||||
Ok(ModuleParts {
|
||||
widget: container,
|
||||
popup: None,
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue