mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-04-19 11:24:24 +02:00
BREAKING CHANGE: To allow for the `name` property, any widgets that were previously targeted by name should be targeted by class instead. This affects **all modules and all popups**, as well as several widgets inside modules. **This will break a lot of rules in your stylesheet**. To attempt to mitigate the damage, a migration script can be found [here](https://raw.githubusercontent.com/JakeStanger/ironbar/master/scripts/migrate-styles.sh) that should get you most of the way. Resolves #75.
124 lines
3.4 KiB
Rust
124 lines
3.4 KiB
Rust
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 chrono::{DateTime, Local};
|
|
use color_eyre::Result;
|
|
use glib::Continue;
|
|
use gtk::prelude::*;
|
|
use gtk::{Align, Button, Calendar, Label, Orientation};
|
|
use serde::Deserialize;
|
|
use tokio::spawn;
|
|
use tokio::sync::mpsc;
|
|
use tokio::time::sleep;
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
pub struct ClockModule {
|
|
/// Date/time format string.
|
|
/// Default: `%d/%m/%Y %H:%M`
|
|
///
|
|
/// Detail on available tokens can be found here:
|
|
/// <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>
|
|
#[serde(default = "default_format")]
|
|
format: String,
|
|
|
|
#[serde(flatten)]
|
|
pub common: Option<CommonConfig>,
|
|
}
|
|
|
|
fn default_format() -> String {
|
|
String::from("%d/%m/%Y %H:%M")
|
|
}
|
|
|
|
impl Module<Button> for ClockModule {
|
|
type SendMessage = DateTime<Local>;
|
|
type ReceiveMessage = ();
|
|
|
|
fn name() -> &'static str {
|
|
"clock"
|
|
}
|
|
|
|
fn spawn_controller(
|
|
&self,
|
|
_info: &ModuleInfo,
|
|
tx: mpsc::Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
|
_rx: mpsc::Receiver<Self::ReceiveMessage>,
|
|
) -> Result<()> {
|
|
spawn(async move {
|
|
loop {
|
|
let date = Local::now();
|
|
send_async!(tx, ModuleUpdateEvent::Update(date));
|
|
sleep(tokio::time::Duration::from_millis(500)).await;
|
|
}
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn into_widget(
|
|
self,
|
|
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
|
info: &ModuleInfo,
|
|
) -> Result<ModuleWidget<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))
|
|
);
|
|
});
|
|
|
|
let format = self.format.clone();
|
|
{
|
|
context.widget_rx.attach(None, move |date| {
|
|
let date_string = format!("{}", date.format(&format));
|
|
label.set_label(&date_string);
|
|
Continue(true)
|
|
});
|
|
}
|
|
|
|
let popup = self.into_popup(context.controller_tx, context.popup_rx, info);
|
|
|
|
Ok(ModuleWidget {
|
|
widget: button,
|
|
popup,
|
|
})
|
|
}
|
|
|
|
fn into_popup(
|
|
self,
|
|
_tx: mpsc::Sender<Self::ReceiveMessage>,
|
|
rx: glib::Receiver<Self::SendMessage>,
|
|
_info: &ModuleInfo,
|
|
) -> Option<gtk::Box> {
|
|
let container = gtk::Box::new(Orientation::Vertical, 0);
|
|
|
|
let clock = Label::builder().halign(Align::Center).build();
|
|
add_class(&clock, "calendar-clock");
|
|
let format = "%H:%M:%S";
|
|
|
|
container.add(&clock);
|
|
|
|
let calendar = Calendar::new();
|
|
add_class(&calendar, "calendar");
|
|
container.add(&calendar);
|
|
|
|
{
|
|
rx.attach(None, move |date| {
|
|
let date_string = format!("{}", date.format(format));
|
|
clock.set_label(&date_string);
|
|
Continue(true)
|
|
});
|
|
}
|
|
|
|
container.show_all();
|
|
|
|
Some(container)
|
|
}
|
|
}
|