Configurable font support
Use fontconfig to load fonts. Fonts can be added to the `fonts` map in the config, and referenced from individual widgets' configurations for customizability. Fonts default to values "mono" and "sans" if nothing is set.
This commit is contained in:
committed by
Kenny Levinsen
parent
1a62696662
commit
48985c470a
+117
-21
@@ -1,13 +1,16 @@
|
||||
use crate::cmd::Cmd;
|
||||
use crate::color::Color;
|
||||
use crate::widget;
|
||||
use crate::widgets;
|
||||
use crate::{
|
||||
fonts::{FontMap, FontRef},
|
||||
widgets,
|
||||
};
|
||||
use chrono::NaiveDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::default::Default;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::{collections::HashMap, sync::mpsc::Sender};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Widget {
|
||||
Margin {
|
||||
@@ -22,16 +25,21 @@ pub enum Widget {
|
||||
HorizontalLayout(Vec<Widget>),
|
||||
VerticalLayout(Vec<Widget>),
|
||||
Clock {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
},
|
||||
Date {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
},
|
||||
Calendar {
|
||||
font_primary: Option<String>,
|
||||
font_secondary: Option<String>,
|
||||
font_size: f32,
|
||||
sections: u32,
|
||||
},
|
||||
Launcher {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
length: u32,
|
||||
#[serde(default)]
|
||||
@@ -42,35 +50,40 @@ pub enum Widget {
|
||||
url_opener: String,
|
||||
},
|
||||
Battery {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
length: u32,
|
||||
},
|
||||
Backlight {
|
||||
#[serde(default)]
|
||||
device: String,
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
length: u32,
|
||||
},
|
||||
#[cfg(feature = "pulseaudio-widget")]
|
||||
PulseAudio {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
length: u32,
|
||||
},
|
||||
#[cfg(feature = "alsa-widget")]
|
||||
AlsaSound {
|
||||
font: Option<String>,
|
||||
font_size: f32,
|
||||
length: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl Widget {
|
||||
pub fn construct(
|
||||
pub fn construct<'a>(
|
||||
self,
|
||||
time: NaiveDateTime,
|
||||
tx: Sender<Cmd>,
|
||||
) -> Option<Box<dyn widget::Widget + Send>> {
|
||||
fonts: &'a FontMap,
|
||||
) -> Option<Box<dyn widget::Widget + Send + 'a>> {
|
||||
match self {
|
||||
Widget::Margin { margins, widget } => match widget.construct(time, tx) {
|
||||
Widget::Margin { margins, widget } => match widget.construct(time, tx, fonts) {
|
||||
Some(w) => Some(widget::Margin::new(margins, w)),
|
||||
None => None,
|
||||
},
|
||||
@@ -78,14 +91,14 @@ impl Widget {
|
||||
width,
|
||||
height,
|
||||
widget,
|
||||
} => match widget.construct(time, tx) {
|
||||
} => match widget.construct(time, tx, fonts) {
|
||||
Some(w) => Some(widget::Fixed::new((width, height), w)),
|
||||
None => None,
|
||||
},
|
||||
Widget::HorizontalLayout(widgets) => Some(widget::HorizontalLayout::new(
|
||||
widgets
|
||||
.into_iter()
|
||||
.map(|x| x.construct(time, tx.clone()))
|
||||
.map(|x| x.construct(time, tx.clone(), fonts))
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.collect(),
|
||||
@@ -93,24 +106,48 @@ impl Widget {
|
||||
Widget::VerticalLayout(widgets) => Some(widget::VerticalLayout::new(
|
||||
widgets
|
||||
.into_iter()
|
||||
.map(|x| x.construct(time, tx.clone()))
|
||||
.map(|x| x.construct(time, tx.clone(), fonts))
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.collect(),
|
||||
)),
|
||||
Widget::Clock { font_size } => Some(widgets::clock::Clock::new(time, font_size)),
|
||||
Widget::Date { font_size } => Some(widgets::date::Date::new(time, font_size)),
|
||||
Widget::Clock { font, font_size } => Some(widgets::clock::Clock::new(
|
||||
time,
|
||||
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
||||
font_size,
|
||||
)),
|
||||
Widget::Date { font, font_size } => Some(widgets::date::Date::new(
|
||||
time,
|
||||
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
||||
font_size,
|
||||
)),
|
||||
Widget::Calendar {
|
||||
font_primary,
|
||||
font_secondary,
|
||||
font_size,
|
||||
sections,
|
||||
} => Some(widgets::calendar::Calendar::new(time, font_size, sections)),
|
||||
} => 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,
|
||||
)),
|
||||
Widget::Launcher {
|
||||
font,
|
||||
font_size,
|
||||
length,
|
||||
app_opener,
|
||||
term_opener,
|
||||
url_opener,
|
||||
} => Some(widgets::launcher::Launcher::new(
|
||||
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
||||
font_size,
|
||||
length,
|
||||
tx,
|
||||
@@ -122,14 +159,24 @@ impl Widget {
|
||||
url_opener
|
||||
},
|
||||
)),
|
||||
Widget::Battery { font_size, length } => {
|
||||
match widgets::battery::UpowerBattery::new(font_size, length, tx) {
|
||||
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,
|
||||
) {
|
||||
Ok(w) => Some(w),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
Widget::Backlight {
|
||||
device,
|
||||
font,
|
||||
font_size,
|
||||
length,
|
||||
} => {
|
||||
@@ -138,21 +185,43 @@ impl Widget {
|
||||
} else {
|
||||
&device
|
||||
};
|
||||
match widgets::backlight::Backlight::new(d, font_size, length) {
|
||||
match widgets::backlight::Backlight::new(
|
||||
d,
|
||||
get_font(&font.or_else(|| Some("sans".to_string())).unwrap(), &fonts),
|
||||
font_size,
|
||||
length,
|
||||
) {
|
||||
Ok(w) => Some(w),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "pulseaudio-widget")]
|
||||
Widget::PulseAudio { font_size, length } => {
|
||||
match widgets::audio::PulseAudio::new(font_size, length, tx) {
|
||||
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,
|
||||
) {
|
||||
Ok(w) => Some(w),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "alsa-widget")]
|
||||
Widget::AlsaSound { font_size, length } => {
|
||||
match widgets::audio::Alsa::new(font_size, length) {
|
||||
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,
|
||||
) {
|
||||
Ok(w) => Some(w),
|
||||
Err(_) => None,
|
||||
}
|
||||
@@ -181,6 +250,7 @@ pub struct Config {
|
||||
pub scale: u32,
|
||||
pub background: Color,
|
||||
pub widget: Widget,
|
||||
pub fonts: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -193,14 +263,21 @@ impl Default for Config {
|
||||
Widget::Margin {
|
||||
margins: (0, 88, 0, 32),
|
||||
widget: Box::new(Widget::VerticalLayout(vec![
|
||||
Widget::Date { font_size: 64.0 },
|
||||
Widget::Clock { font_size: 256.0 },
|
||||
Widget::Date {
|
||||
font: None,
|
||||
font_size: 64.0,
|
||||
},
|
||||
Widget::Clock {
|
||||
font: None,
|
||||
font_size: 256.0,
|
||||
},
|
||||
])),
|
||||
},
|
||||
Widget::VerticalLayout(vec![
|
||||
Widget::Margin {
|
||||
margins: (0, 0, 0, 8),
|
||||
widget: Box::new(Widget::Battery {
|
||||
font: None,
|
||||
font_size: 24.0,
|
||||
length: 600,
|
||||
}),
|
||||
@@ -209,6 +286,7 @@ impl Default for Config {
|
||||
margins: (0, 0, 0, 8),
|
||||
widget: Box::new(Widget::Backlight {
|
||||
device: "intel_backlight".to_string(),
|
||||
font: None,
|
||||
font_size: 24.0,
|
||||
length: 600,
|
||||
}),
|
||||
@@ -217,6 +295,7 @@ impl Default for Config {
|
||||
Widget::Margin {
|
||||
margins: (0, 0, 0, 8),
|
||||
widget: Box::new(Widget::PulseAudio {
|
||||
font: None,
|
||||
font_size: 24.0,
|
||||
length: 600,
|
||||
}),
|
||||
@@ -224,10 +303,13 @@ impl Default for Config {
|
||||
]),
|
||||
]),
|
||||
Widget::Calendar {
|
||||
font_primary: None,
|
||||
font_secondary: None,
|
||||
font_size: 16.0,
|
||||
sections: 3,
|
||||
},
|
||||
Widget::Launcher {
|
||||
font: None,
|
||||
font_size: 32.0,
|
||||
length: 1200,
|
||||
app_opener: "".to_string(),
|
||||
@@ -239,6 +321,20 @@ impl Default for Config {
|
||||
output_mode: Default::default(),
|
||||
scale: 1,
|
||||
background: Color::new(0.0, 0.0, 0.0, 0.9),
|
||||
fonts: {
|
||||
let mut map = HashMap::with_capacity(2);
|
||||
map.insert("mono".to_string(), "mono".to_string());
|
||||
map.insert("sans".to_string(), "sans".to_string());
|
||||
map
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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)),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user