2019-09-06 21:54:04 +02:00
|
|
|
use crate::cmd::Cmd;
|
2019-09-07 00:33:24 +02:00
|
|
|
use crate::color::Color;
|
2019-09-06 21:54:04 +02:00
|
|
|
use crate::widget;
|
2020-06-03 21:06:06 +02:00
|
|
|
use crate::{
|
|
|
|
|
fonts::{FontMap, FontRef},
|
|
|
|
|
widgets,
|
|
|
|
|
};
|
2020-04-22 00:52:08 +02:00
|
|
|
use chrono::NaiveDateTime;
|
2019-09-06 21:54:04 +02:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::default::Default;
|
2020-06-03 21:06:06 +02:00
|
|
|
use std::{collections::HashMap, sync::mpsc::Sender};
|
2019-09-06 21:54:04 +02:00
|
|
|
|
2020-06-03 21:06:06 +02:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
2019-09-06 21:54:04 +02:00
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub enum Widget {
|
|
|
|
|
Margin {
|
2019-09-06 22:48:50 +02:00
|
|
|
margins: (u32, u32, u32, u32),
|
2019-09-06 21:54:04 +02:00
|
|
|
widget: Box<Widget>,
|
|
|
|
|
},
|
|
|
|
|
Fixed {
|
|
|
|
|
width: u32,
|
|
|
|
|
height: u32,
|
|
|
|
|
widget: Box<Widget>,
|
|
|
|
|
},
|
2020-04-22 01:31:22 +02:00
|
|
|
HorizontalLayout(Vec<Widget>),
|
|
|
|
|
VerticalLayout(Vec<Widget>),
|
2019-09-06 21:54:04 +02:00
|
|
|
Clock {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
},
|
|
|
|
|
Date {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
},
|
|
|
|
|
Calendar {
|
2020-06-03 21:06:06 +02:00
|
|
|
font_primary: Option<String>,
|
|
|
|
|
font_secondary: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
sections: u32,
|
|
|
|
|
},
|
|
|
|
|
Launcher {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
length: u32,
|
2019-09-06 22:48:50 +02:00
|
|
|
#[serde(default)]
|
2019-09-06 21:54:04 +02:00
|
|
|
app_opener: String,
|
2019-09-06 22:48:50 +02:00
|
|
|
#[serde(default)]
|
2019-09-06 21:54:04 +02:00
|
|
|
term_opener: String,
|
2019-09-06 22:48:50 +02:00
|
|
|
#[serde(default)]
|
2019-09-06 21:54:04 +02:00
|
|
|
url_opener: String,
|
|
|
|
|
},
|
|
|
|
|
Battery {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
length: u32,
|
|
|
|
|
},
|
|
|
|
|
Backlight {
|
2020-01-01 17:18:25 +01:00
|
|
|
#[serde(default)]
|
|
|
|
|
device: String,
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
length: u32,
|
|
|
|
|
},
|
2019-10-02 16:25:43 +02:00
|
|
|
#[cfg(feature = "pulseaudio-widget")]
|
2019-09-06 21:54:04 +02:00
|
|
|
PulseAudio {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size: f32,
|
|
|
|
|
length: u32,
|
|
|
|
|
},
|
2019-10-02 16:25:43 +02:00
|
|
|
#[cfg(feature = "alsa-widget")]
|
2019-09-18 16:19:10 +07:00
|
|
|
AlsaSound {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: Option<String>,
|
2019-09-18 16:19:10 +07:00
|
|
|
font_size: f32,
|
2019-10-02 16:25:43 +02:00
|
|
|
length: u32,
|
|
|
|
|
},
|
2019-09-06 21:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Widget {
|
2020-06-03 21:06:06 +02:00
|
|
|
pub fn construct<'a>(
|
2020-04-22 00:52:08 +02:00
|
|
|
self,
|
2020-04-22 01:31:22 +02:00
|
|
|
time: NaiveDateTime,
|
2020-04-22 00:52:08 +02:00
|
|
|
tx: Sender<Cmd>,
|
2020-06-03 21:06:06 +02:00
|
|
|
fonts: &'a FontMap,
|
|
|
|
|
) -> Option<Box<dyn widget::Widget + Send + 'a>> {
|
2019-09-06 21:54:04 +02:00
|
|
|
match self {
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::Margin { margins, widget } => match widget.construct(time, tx, fonts) {
|
2019-09-06 21:54:04 +02:00
|
|
|
Some(w) => Some(widget::Margin::new(margins, w)),
|
|
|
|
|
None => None,
|
|
|
|
|
},
|
|
|
|
|
Widget::Fixed {
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
widget,
|
2020-06-03 21:06:06 +02:00
|
|
|
} => match widget.construct(time, tx, fonts) {
|
2019-09-06 21:54:04 +02:00
|
|
|
Some(w) => Some(widget::Fixed::new((width, height), w)),
|
|
|
|
|
None => None,
|
|
|
|
|
},
|
|
|
|
|
Widget::HorizontalLayout(widgets) => Some(widget::HorizontalLayout::new(
|
|
|
|
|
widgets
|
|
|
|
|
.into_iter()
|
2020-06-03 21:06:06 +02:00
|
|
|
.map(|x| x.construct(time, tx.clone(), fonts))
|
2019-09-06 21:54:04 +02:00
|
|
|
.filter(|x| x.is_some())
|
|
|
|
|
.map(|x| x.unwrap())
|
|
|
|
|
.collect(),
|
|
|
|
|
)),
|
|
|
|
|
Widget::VerticalLayout(widgets) => Some(widget::VerticalLayout::new(
|
|
|
|
|
widgets
|
|
|
|
|
.into_iter()
|
2020-06-03 21:06:06 +02:00
|
|
|
.map(|x| x.construct(time, tx.clone(), fonts))
|
2019-09-06 21:54:04 +02:00
|
|
|
.filter(|x| x.is_some())
|
|
|
|
|
.map(|x| x.unwrap())
|
|
|
|
|
.collect(),
|
|
|
|
|
)),
|
2020-06-14 15:32:11 +02:00
|
|
|
Widget::Clock { font, font_size } => match widgets::clock::Clock::new(
|
2020-06-03 21:06:06 +02:00
|
|
|
time,
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
2020-06-14 15:32:11 +02:00
|
|
|
) {
|
|
|
|
|
Ok(w) => Some(w),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
},
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::Date { font, font_size } => Some(widgets::date::Date::new(
|
|
|
|
|
time,
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
|
|
|
|
)),
|
2019-09-06 21:54:04 +02:00
|
|
|
Widget::Calendar {
|
2020-06-03 21:06:06 +02:00
|
|
|
font_primary,
|
|
|
|
|
font_secondary,
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size,
|
|
|
|
|
sections,
|
2020-06-03 21:06:06 +02:00
|
|
|
} => Some(widgets::calendar::Calendar::new(
|
|
|
|
|
time,
|
|
|
|
|
get_font(
|
|
|
|
|
&font_primary.or_else(|| Some("sans".to_string())).unwrap(),
|
|
|
|
|
&fonts,
|
|
|
|
|
),
|
|
|
|
|
get_font(
|
|
|
|
|
&font_secondary.or_else(|| Some("mono".to_string())).unwrap(),
|
|
|
|
|
&fonts,
|
|
|
|
|
),
|
|
|
|
|
font_size,
|
|
|
|
|
sections,
|
|
|
|
|
)),
|
2019-09-06 22:48:50 +02:00
|
|
|
Widget::Launcher {
|
2020-06-03 21:06:06 +02:00
|
|
|
font,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
app_opener,
|
|
|
|
|
term_opener,
|
|
|
|
|
url_opener,
|
|
|
|
|
} => Some(widgets::launcher::Launcher::new(
|
2020-06-03 21:06:06 +02:00
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
2019-09-06 21:54:04 +02:00
|
|
|
font_size,
|
|
|
|
|
length,
|
2020-04-22 01:31:22 +02:00
|
|
|
tx,
|
2019-09-06 21:54:04 +02:00
|
|
|
app_opener,
|
|
|
|
|
term_opener,
|
2020-04-22 01:31:22 +02:00
|
|
|
if url_opener.is_empty() {
|
2019-09-06 22:48:50 +02:00
|
|
|
"xdg_open ".to_string()
|
|
|
|
|
} else {
|
|
|
|
|
url_opener
|
|
|
|
|
},
|
2019-09-06 21:54:04 +02:00
|
|
|
)),
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::Battery {
|
|
|
|
|
font,
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
} => {
|
|
|
|
|
match widgets::battery::UpowerBattery::new(
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
tx,
|
|
|
|
|
) {
|
2019-09-06 21:54:04 +02:00
|
|
|
Ok(w) => Some(w),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-08 11:31:56 +01:00
|
|
|
Widget::Backlight {
|
|
|
|
|
device,
|
2020-06-03 21:06:06 +02:00
|
|
|
font,
|
2020-01-08 11:31:56 +01:00
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
} => {
|
2020-01-01 17:18:25 +01:00
|
|
|
let d = if device == "" {
|
|
|
|
|
"intel_backlight"
|
|
|
|
|
} else {
|
|
|
|
|
&device
|
|
|
|
|
};
|
2020-06-03 21:06:06 +02:00
|
|
|
match widgets::backlight::Backlight::new(
|
|
|
|
|
d,
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
) {
|
2019-09-06 21:54:04 +02:00
|
|
|
Ok(w) => Some(w),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-02 16:25:43 +02:00
|
|
|
#[cfg(feature = "pulseaudio-widget")]
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::PulseAudio {
|
|
|
|
|
font,
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
} => {
|
|
|
|
|
match widgets::audio::PulseAudio::new(
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
tx,
|
|
|
|
|
) {
|
2019-09-18 16:19:10 +07:00
|
|
|
Ok(w) => Some(w),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-02 16:25:43 +02:00
|
|
|
#[cfg(feature = "alsa-widget")]
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::AlsaSound {
|
|
|
|
|
font,
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
} => {
|
|
|
|
|
match widgets::audio::Alsa::new(
|
|
|
|
|
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
|
|
|
|
font_size,
|
|
|
|
|
length,
|
|
|
|
|
) {
|
2019-09-06 21:54:04 +02:00
|
|
|
Ok(w) => Some(w),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub enum OutputMode {
|
2019-09-06 22:48:50 +02:00
|
|
|
All,
|
|
|
|
|
Active,
|
2019-09-06 21:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for OutputMode {
|
2019-09-06 22:48:50 +02:00
|
|
|
fn default() -> Self {
|
|
|
|
|
OutputMode::Active
|
|
|
|
|
}
|
2019-09-06 21:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-14 16:24:32 +02:00
|
|
|
fn default_fonts() -> HashMap<String, String> {
|
|
|
|
|
let mut map = HashMap::with_capacity(2);
|
|
|
|
|
map.insert("mono".to_string(), "mono".to_string());
|
|
|
|
|
map.insert("sans".to_string(), "sans".to_string());
|
|
|
|
|
map
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 21:54:04 +02:00
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub struct Config {
|
|
|
|
|
pub output_mode: OutputMode,
|
|
|
|
|
pub scale: u32,
|
2019-09-07 00:24:58 +02:00
|
|
|
pub background: Color,
|
2019-09-07 12:26:30 +02:00
|
|
|
pub widget: Widget,
|
2020-06-14 16:24:32 +02:00
|
|
|
|
|
|
|
|
#[serde(default = "default_fonts")]
|
2020-06-03 21:06:06 +02:00
|
|
|
pub fonts: HashMap<String, String>,
|
2019-09-06 21:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Config {
|
2019-09-06 22:48:50 +02:00
|
|
|
fn default() -> Self {
|
|
|
|
|
Config {
|
|
|
|
|
widget: Widget::Margin {
|
|
|
|
|
margins: (20, 20, 20, 20),
|
|
|
|
|
widget: Box::new(Widget::VerticalLayout(vec![
|
2020-04-22 01:31:22 +02:00
|
|
|
Widget::HorizontalLayout(vec![
|
|
|
|
|
Widget::Margin {
|
2019-09-06 22:48:50 +02:00
|
|
|
margins: (0, 88, 0, 32),
|
|
|
|
|
widget: Box::new(Widget::VerticalLayout(vec![
|
2020-06-03 21:06:06 +02:00
|
|
|
Widget::Date {
|
|
|
|
|
font: None,
|
|
|
|
|
font_size: 64.0,
|
|
|
|
|
},
|
|
|
|
|
Widget::Clock {
|
|
|
|
|
font: None,
|
|
|
|
|
font_size: 256.0,
|
|
|
|
|
},
|
2019-09-06 22:48:50 +02:00
|
|
|
])),
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
|
|
|
|
Widget::VerticalLayout(vec![
|
|
|
|
|
Widget::Margin {
|
2019-09-06 22:48:50 +02:00
|
|
|
margins: (0, 0, 0, 8),
|
|
|
|
|
widget: Box::new(Widget::Battery {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: None,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size: 24.0,
|
2020-06-14 15:34:19 +02:00
|
|
|
length: 0,
|
2019-09-06 22:48:50 +02:00
|
|
|
}),
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
|
|
|
|
Widget::Margin {
|
2019-09-06 22:48:50 +02:00
|
|
|
margins: (0, 0, 0, 8),
|
|
|
|
|
widget: Box::new(Widget::Backlight {
|
2020-01-01 17:18:25 +01:00
|
|
|
device: "intel_backlight".to_string(),
|
2020-06-03 21:06:06 +02:00
|
|
|
font: None,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size: 24.0,
|
2020-06-14 15:34:19 +02:00
|
|
|
length: 0,
|
2019-09-06 22:48:50 +02:00
|
|
|
}),
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
2019-10-02 16:25:43 +02:00
|
|
|
#[cfg(feature = "pulseaudio-widget")]
|
2020-04-22 01:31:22 +02:00
|
|
|
Widget::Margin {
|
2019-09-06 22:48:50 +02:00
|
|
|
margins: (0, 0, 0, 8),
|
|
|
|
|
widget: Box::new(Widget::PulseAudio {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: None,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size: 24.0,
|
2020-06-14 15:34:19 +02:00
|
|
|
length: 0,
|
2019-09-06 22:48:50 +02:00
|
|
|
}),
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
|
|
|
|
]),
|
|
|
|
|
]),
|
|
|
|
|
Widget::Calendar {
|
2020-06-03 21:06:06 +02:00
|
|
|
font_primary: None,
|
|
|
|
|
font_secondary: None,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size: 16.0,
|
|
|
|
|
sections: 3,
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
|
|
|
|
Widget::Launcher {
|
2020-06-03 21:06:06 +02:00
|
|
|
font: None,
|
2019-09-06 22:48:50 +02:00
|
|
|
font_size: 32.0,
|
2020-06-14 15:34:19 +02:00
|
|
|
length: 0,
|
2019-09-06 22:48:50 +02:00
|
|
|
app_opener: "".to_string(),
|
|
|
|
|
term_opener: "".to_string(),
|
|
|
|
|
url_opener: "".to_string(),
|
2020-04-22 01:31:22 +02:00
|
|
|
},
|
2019-09-06 22:48:50 +02:00
|
|
|
])),
|
|
|
|
|
},
|
|
|
|
|
output_mode: Default::default(),
|
|
|
|
|
scale: 1,
|
2019-09-07 00:24:58 +02:00
|
|
|
background: Color::new(0.0, 0.0, 0.0, 0.9),
|
2020-06-14 16:24:32 +02:00
|
|
|
fonts: default_fonts(),
|
2019-09-06 22:48:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-03 21:06:06 +02:00
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_font<'a>(name: &str, map: &'a FontMap) -> FontRef<'a> {
|
|
|
|
|
match map.get(name) {
|
|
|
|
|
Some(f) => f,
|
|
|
|
|
None => panic!(format!("Font {} is missing from the config", name)),
|
|
|
|
|
}
|
|
|
|
|
}
|