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:
Hilmar Gústafsson
2020-06-14 17:01:42 +02:00
committed by Kenny Levinsen
parent 1a62696662
commit 48985c470a
26 changed files with 396 additions and 14128 deletions
+6 -6
View File
@@ -199,19 +199,19 @@ impl AppInner {
}
}
pub struct App {
pub struct App<'a> {
pools: DoubleMemPool,
display: Display,
event_queue: EventQueue,
cmd_queue: Arc<Mutex<VecDeque<Cmd>>>,
widget: Option<Box<dyn Widget + Send>>,
widget: Option<Box<dyn Widget + Send + 'a>>,
bg: Color,
inner: Arc<Mutex<AppInner>>,
last_damage: Option<Vec<(i32, i32, i32, i32)>>,
last_dim: (u32, u32),
}
impl App {
impl<'a> App<'a> {
pub fn redraw(&mut self, force: bool) -> Result<(), ::std::io::Error> {
let widget = match self.widget {
Some(ref mut widget) => widget,
@@ -341,16 +341,16 @@ impl App {
&mut self.event_queue
}
pub fn get_widget(&mut self) -> &mut Box<dyn Widget + Send> {
pub fn get_widget(&mut self) -> &mut Box<dyn Widget + Send + 'a> {
self.widget.as_mut().unwrap()
}
pub fn set_widget(&mut self, w: Box<dyn Widget + Send>) -> Result<(), ::std::io::Error> {
pub fn set_widget(&mut self, w: Box<dyn Widget + Send + 'a>) -> Result<(), ::std::io::Error> {
self.widget = Some(w);
self.redraw(true)
}
pub fn new(tx: Sender<Cmd>, output_mode: OutputMode, bg: Color, scale: u32) -> App {
pub fn new(tx: Sender<Cmd>, output_mode: OutputMode, bg: Color, scale: u32) -> App<'a> {
let inner = Arc::new(Mutex::new(AppInner::new(tx, output_mode, scale)));
//
+117 -21
View File
@@ -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)),
}
}
+7 -21
View File
@@ -1,23 +1,9 @@
use crate::buffer::Buffer;
use crate::color::Color;
use crate::{color::Color, fonts::FontRef};
use rusttype::{point, Scale};
use std::collections::HashMap;
use lazy_static::lazy_static;
use rusttype::{point, Font as RustFont, Scale};
pub static DEJAVUSANS_MONO_FONT_DATA: &[u8] = include_bytes!("../fonts/dejavu/DejaVuSansMono.ttf");
pub static ROBOTO_REGULAR_FONT_DATA: &[u8] = include_bytes!("../fonts/Roboto-Regular.ttf");
lazy_static! {
pub static ref DEJAVUSANS_MONO: RustFont<'static> =
RustFont::from_bytes(DEJAVUSANS_MONO_FONT_DATA as &[u8])
.expect("error constructing DejaVuSansMono");
pub static ref ROBOTO_REGULAR: RustFont<'static> =
RustFont::from_bytes(ROBOTO_REGULAR_FONT_DATA as &[u8])
.expect("error constructing Roboto-Regular");
}
struct CachedGlyph {
dimensions: (u32, u32),
origin: (i32, i32),
@@ -25,7 +11,7 @@ struct CachedGlyph {
}
impl CachedGlyph {
fn new(font: &RustFont, size: f32, ch: char) -> CachedGlyph {
fn new(font: FontRef, size: f32, ch: char) -> CachedGlyph {
let scale = Scale::uniform(size);
let v_metrics = font.v_metrics(scale);
let glyph = font
@@ -81,14 +67,14 @@ impl CachedGlyph {
}
}
pub struct Font {
pub struct Font<'a> {
glyphs: HashMap<char, CachedGlyph>,
font: &'static RustFont<'static>,
font: FontRef<'a>,
size: f32,
}
impl Font {
pub fn new(font: &'static RustFont, size: f32) -> Font {
impl<'a> Font<'a> {
pub fn new(font: FontRef<'a>, size: f32) -> Font {
Font {
glyphs: HashMap::new(),
font,
+47
View File
@@ -0,0 +1,47 @@
//! Utility module for fonts
use fontconfig::Fontconfig as FontConfig;
use rusttype::Font;
use std::{
collections::HashMap,
fs::File,
io::Read,
path::{Path, PathBuf},
};
/// FontMap is used to store different font configurations
pub type FontMap<'a> = HashMap<String, rusttype::Font<'a>>;
/// FontRef is used to store Fonts on widgets.
pub type FontRef<'a> = &'a rusttype::Font<'a>;
/// FontSeeker is a marker struct that is used to look up fonts
pub(crate) struct FontSeeker;
impl FontSeeker {
/// Acts like fc-match.
/// Given a string, it matches it to a font file and returns its path.
pub(crate) fn from_string(name: &str) -> PathBuf {
let fc = FontConfig::new().unwrap();
fc.find(name, None).unwrap().path
}
}
/// FontLoader is a marker struct that is used to load files
pub(crate) struct FontLoader;
impl FontLoader {
/// Given a path, loads it as a Font, which can be rendered to the screen.
pub(crate) fn from_path<'a, P>(path: P) -> Option<Font<'a>>
where
P: AsRef<Path>,
{
let mut file = File::open(path).expect("Font file not found");
let mut data = match file.metadata() {
Ok(metadata) => Vec::with_capacity(metadata.len() as usize),
Err(_) => vec![],
};
file.read_to_end(&mut data).unwrap();
Font::try_from_vec(data)
}
}
+22 -13
View File
@@ -3,7 +3,7 @@ use std::fs::File;
use std::io::{BufRead, BufReader, Read, Write};
use std::os::unix::io::AsRawFd;
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::mpsc::channel;
use std::{collections::HashMap, sync::mpsc::channel};
use chrono::{Duration, Local};
use nix::poll::{poll, PollFd, PollFlags};
@@ -19,6 +19,7 @@ mod configfmt;
mod desktop;
mod doublemempool;
mod draw;
mod fonts;
mod widget;
mod widgets;
@@ -26,6 +27,7 @@ use app::{App, OutputMode};
use cmd::Cmd;
use config::Config;
use configfmt::ConfigFmt;
use fonts::{FontLoader, FontMap, FontSeeker};
use widget::WaitContext;
enum Mode {
@@ -79,6 +81,19 @@ fn main() {
let scale = config.scale;
let fonts: FontMap = {
let load_font = |font_name| {
let path = FontSeeker::from_string(font_name);
FontLoader::from_path(&path).expect(&format!("Loading {} failed", path.display()))
};
config
.fonts
.iter()
.map(|(key, val)| (key.clone(), load_font(val)))
.collect::<HashMap<_, _>>()
};
let mut args = env::args();
let _ = args.next();
let mode = match args.next() {
@@ -159,17 +174,12 @@ fn main() {
let (tx_draw, rx_draw) = channel();
let tx_draw_mod = tx_draw.clone();
let (mod_tx, mod_rx) = channel();
std::thread::spawn(move || {
// Print, write to a file, or send to an HTTP server.
match config
.widget
.construct(Local::now().naive_local(), tx_draw_mod)
{
Some(w) => mod_tx.send(w).unwrap(),
None => panic!("no widget configured"),
}
});
// Print, write to a file, or send to an HTTP server.
let widget = config
.widget
.construct(Local::now().naive_local(), tx_draw_mod, &fonts)
.expect("no widget configured");
let mut app = App::new(tx_draw, output_mode, background, scale);
if daemon {
@@ -177,7 +187,6 @@ fn main() {
} else {
app.show();
}
let widget = mod_rx.recv().unwrap();
app.set_widget(widget).unwrap();
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
+20 -20
View File
@@ -69,18 +69,18 @@ pub trait Widget {
fn mouse_scroll(&mut self, scroll: (f64, f64), pos: (u32, u32));
}
pub struct VerticalLayout {
pub children: Vec<Box<dyn Widget + Send>>,
pub struct VerticalLayout<'a> {
pub children: Vec<Box<dyn Widget + Send + 'a>>,
}
#[allow(dead_code)]
impl VerticalLayout {
pub fn new(children: Vec<Box<dyn Widget + Send>>) -> Box<VerticalLayout> {
impl<'a> VerticalLayout<'a> {
pub fn new(children: Vec<Box<dyn Widget + Send + 'a>>) -> Box<VerticalLayout> {
Box::new(VerticalLayout { children })
}
}
impl Widget for VerticalLayout {
impl<'a> Widget for VerticalLayout<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
for child in &mut self.children {
child.wait(ctx);
@@ -180,18 +180,18 @@ impl Widget for VerticalLayout {
}
}
pub struct HorizontalLayout {
pub children: Vec<Box<dyn Widget + Send>>,
pub struct HorizontalLayout<'a> {
pub children: Vec<Box<dyn Widget + Send + 'a>>,
}
#[allow(dead_code)]
impl HorizontalLayout {
pub fn new(children: Vec<Box<dyn Widget + Send>>) -> Box<HorizontalLayout> {
impl<'a> HorizontalLayout<'a> {
pub fn new(children: Vec<Box<dyn Widget + Send + 'a>>) -> Box<HorizontalLayout> {
Box::new(HorizontalLayout { children })
}
}
impl Widget for HorizontalLayout {
impl<'a> Widget for HorizontalLayout<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
for child in &mut self.children {
child.wait(ctx);
@@ -293,19 +293,19 @@ impl Widget for HorizontalLayout {
}
}
pub struct Margin {
pub child: Box<dyn Widget + Send>,
pub struct Margin<'a> {
pub child: Box<dyn Widget + Send + 'a>,
pub margins: (u32, u32, u32, u32), // left, right, top, bottom
}
#[allow(dead_code)]
impl Margin {
pub fn new(margins: (u32, u32, u32, u32), child: Box<dyn Widget + Send>) -> Box<Margin> {
impl<'a> Margin<'a> {
pub fn new(margins: (u32, u32, u32, u32), child: Box<dyn Widget + Send + 'a>) -> Box<Margin> {
Box::new(Margin { child, margins })
}
}
impl Widget for Margin {
impl<'a> Widget for Margin<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
self.child.wait(ctx)
}
@@ -367,19 +367,19 @@ impl Widget for Margin {
}
}
pub struct Fixed {
pub child: Box<dyn Widget + Send>,
pub struct Fixed<'a> {
pub child: Box<dyn Widget + Send + 'a>,
pub size: (u32, u32),
}
#[allow(dead_code)]
impl Fixed {
pub fn new(size: (u32, u32), child: Box<dyn Widget + Send>) -> Box<Fixed> {
impl<'a> Fixed<'a> {
pub fn new(size: (u32, u32), child: Box<dyn Widget + Send + 'a>) -> Box<Fixed> {
Box::new(Fixed { child, size })
}
}
impl Widget for Fixed {
impl<'a> Widget for Fixed<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
self.child.wait(ctx)
}
+12 -4
View File
@@ -1,6 +1,9 @@
use crate::color::Color;
use crate::widget::WaitContext;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::{
fonts::FontRef,
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use alsa::mixer::{Mixer, Selem, SelemChannelId, SelemId};
@@ -34,15 +37,20 @@ pub struct Alsa {
}
impl Alsa {
pub fn new(font_size: f32, length: u32) -> ::std::io::Result<Box<BarWidget>> {
pub fn new(font: FontRef, font_size: f32, length: u32) -> ::std::io::Result<Box<BarWidget>> {
let mixer = Mixer::new(CARD_NAME, true)
.map_err(|err| alsa_error_to_io_error("Failed to create ALSA mixer", &err))?;
let mixer = Self { mixer };
mixer.get_master_volume()?; // probing
Ok(BarWidget::new_simple(font_size, length, Box::new(mixer)))
Ok(BarWidget::new_simple(
font,
font_size,
length,
Box::new(mixer),
))
}
#[inline]
pub fn get_master<'a>(&'a self) -> ::std::io::Result<Selem<'a>> {
pub fn get_master(&self) -> ::std::io::Result<Selem> {
let master_id = SelemId::new(SELEM_NAME, SELEM_ID);
match self.mixer.find_selem(&master_id) {
Some(master) => Ok(master),
+6 -2
View File
@@ -1,7 +1,10 @@
use crate::cmd::Cmd;
use crate::color::Color;
use crate::widget::WaitContext;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::{
fonts::FontRef,
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use std::cell::RefCell;
use std::collections::HashMap;
@@ -484,11 +487,12 @@ pub struct PulseAudio {
impl PulseAudio {
pub fn new(
font: FontRef,
font_size: f32,
length: u32,
sender: Sender<Cmd>,
) -> Result<Box<BarWidget>, ::std::io::Error> {
BarWidget::new(font_size, length, move |dirty| {
BarWidget::new(font, font_size, length, move |dirty| {
let device = PulseAudioSoundDevice::new(move || {
*dirty.lock().unwrap() = true;
sender.send(Cmd::Draw).unwrap();
+16 -3
View File
@@ -1,6 +1,9 @@
use crate::color::Color;
use crate::widget::WaitContext;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::{
fonts::FontRef,
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use std::fs;
use std::fs::OpenOptions;
@@ -70,7 +73,12 @@ impl Backlight {
Ok(())
}
pub fn new(path: &str, font_size: f32, length: u32) -> Result<Box<BarWidget>, Error> {
pub fn new<'a>(
path: &str,
font: FontRef<'a>,
font_size: f32,
length: u32,
) -> Result<Box<BarWidget<'a>>, Error> {
let mut dev = Backlight {
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
cur_brightness: 0,
@@ -79,7 +87,12 @@ impl Backlight {
dev.update()?;
Ok(BarWidget::new_simple(font_size, length, Box::new(dev)))
Ok(BarWidget::new_simple(
font,
font_size,
length,
Box::new(dev),
))
}
}
+19 -10
View File
@@ -1,6 +1,9 @@
use crate::color::Color;
use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR};
use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget};
use crate::draw::{draw_bar, draw_box, Font};
use crate::{
fonts::FontRef,
widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget},
};
use std::sync::{Arc, Mutex};
@@ -14,21 +17,22 @@ pub trait BarWidgetImpl {
fn toggle(&mut self);
}
pub struct BarWidget {
pub struct BarWidget<'a> {
bar_impl: Box<dyn BarWidgetImpl + Send>,
font: Font,
font: Font<'a>,
font_size: u32,
length: u32,
dirty: Arc<Mutex<bool>>,
}
impl BarWidget {
impl<'a> BarWidget<'a> {
pub fn new_simple(
font: FontRef,
font_size: f32,
length: u32,
w: Box<dyn BarWidgetImpl + Send>,
) -> Box<BarWidget> {
let mut font = Font::new(&ROBOTO_REGULAR, font_size);
let mut font = Font::new(font, font_size);
font.add_str_to_cache(w.name());
Box::new(BarWidget {
@@ -40,15 +44,20 @@ impl BarWidget {
})
}
pub fn new<F>(font_size: f32, length: u32, f: F) -> Result<Box<BarWidget>, ::std::io::Error>
pub fn new<F>(
font: FontRef<'a>,
font_size: f32,
length: u32,
f: F,
) -> Result<Box<BarWidget>, ::std::io::Error>
where
F: FnOnce(Arc<Mutex<bool>>) -> Result<Box<dyn BarWidgetImpl + Send>, ::std::io::Error>,
F: Send + 'static + Clone,
F: Send + 'a + Clone,
{
let dirty = Arc::new(Mutex::new(true));
let im = f(dirty.clone())?;
let mut font = Font::new(&ROBOTO_REGULAR, font_size);
let mut font = Font::new(font, font_size);
font.add_str_to_cache(im.name());
Ok(Box::new(BarWidget {
@@ -61,7 +70,7 @@ impl BarWidget {
}
}
impl Widget for BarWidget {
impl<'a> Widget for BarWidget<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
self.bar_impl.wait(ctx);
}
+6 -2
View File
@@ -1,7 +1,10 @@
use crate::cmd::Cmd;
use crate::color::Color;
use crate::widget::WaitContext;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use crate::{
fonts::FontRef,
widgets::bar_widget::{BarWidget, BarWidgetImpl},
};
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
@@ -161,11 +164,12 @@ impl UpowerBattery {
}
pub fn new(
font: FontRef,
font_size: f32,
length: u32,
sender: Sender<Cmd>,
) -> Result<Box<BarWidget>, ::std::io::Error> {
BarWidget::new(font_size, length, move |dirty| {
BarWidget::new(font, font_size, length, move |dirty| {
let d = UpowerBattery::from_device(dirty, sender, "DisplayDevice")?;
Ok(Box::new(d))
})
+24 -15
View File
@@ -1,23 +1,26 @@
use crate::buffer::Buffer;
use crate::color::Color;
use crate::draw::{Font, DEJAVUSANS_MONO, ROBOTO_REGULAR};
use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget};
use crate::draw::Font;
use crate::{
fonts::FontRef,
widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget},
};
use chrono::{Datelike, NaiveDate, NaiveDateTime};
pub struct Calendar {
pub struct Calendar<'a> {
cur_date: NaiveDate,
dirty: bool,
offset: f64,
sections: u32,
font_size: u32,
calendar_cache: Font,
month_cache: Font,
year_cache: Font,
day_cache: Font,
calendar_cache: Font<'a>,
month_cache: Font<'a>,
year_cache: Font<'a>,
day_cache: Font<'a>,
}
impl Calendar {
impl<'a> Calendar<'a> {
fn draw_month(
&self,
buf: &mut Buffer,
@@ -152,15 +155,21 @@ impl Calendar {
}
}
impl Calendar {
pub fn new(time: NaiveDateTime, font_size: f32, sections: u32) -> Box<Calendar> {
let mut calendar_cache = Font::new(&DEJAVUSANS_MONO, font_size * 2.0);
impl<'a> Calendar<'a> {
pub fn new(
time: NaiveDateTime,
font_primary: FontRef<'a>,
font_secondary: FontRef<'a>,
font_size: f32,
sections: u32,
) -> Box<Calendar<'a>> {
let mut calendar_cache = Font::new(font_secondary, font_size * 2.0);
calendar_cache.add_str_to_cache("0123456789");
let mut month_cache = Font::new(&ROBOTO_REGULAR, font_size * 4.0);
let mut month_cache = Font::new(font_primary, font_size * 4.0);
month_cache.add_str_to_cache("JanuryFebMchApilJgstSmOoNvD");
let mut year_cache = Font::new(&DEJAVUSANS_MONO, font_size * 1.5);
let mut year_cache = Font::new(font_primary, font_size * 1.5);
year_cache.add_str_to_cache("-0123456789");
let mut day_cache = Font::new(&DEJAVUSANS_MONO, font_size);
let mut day_cache = Font::new(font_primary, font_size);
day_cache.add_str_to_cache("MONTUEWDHFRISA");
Box::new(Calendar {
cur_date: time.date(),
@@ -176,7 +185,7 @@ impl Calendar {
}
}
impl Widget for Calendar {
impl<'a> Widget for Calendar<'a> {
fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {}
fn leave(&mut self) {}
+11 -8
View File
@@ -1,18 +1,21 @@
use crate::color::Color;
use crate::draw::{Font, ROBOTO_REGULAR};
use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget};
use crate::draw::Font;
use crate::{
fonts::FontRef,
widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget},
};
use chrono::{Duration, NaiveDateTime, Timelike};
pub struct Clock {
pub struct Clock<'a> {
cur_time: NaiveDateTime,
clock_cache: Font,
clock_cache: Font<'a>,
size: f32,
}
impl Clock {
pub fn new(time: NaiveDateTime, size: f32) -> Box<Clock> {
let mut clock_cache = Font::new(&ROBOTO_REGULAR, size);
impl<'a> Clock<'a> {
pub fn new(time: NaiveDateTime, font: FontRef, size: f32) -> Box<Clock> {
let mut clock_cache = Font::new(font, size);
clock_cache.add_str_to_cache("0123456789:");
Box::new(Clock {
@@ -23,7 +26,7 @@ impl Clock {
}
}
impl Widget for Clock {
impl<'a> Widget for Clock<'a> {
fn wait(&mut self, ctx: &mut WaitContext) {
let target = (self.cur_time + Duration::seconds(60))
.with_second(0)
+11 -8
View File
@@ -1,18 +1,21 @@
use crate::color::Color;
use crate::draw::{Font, ROBOTO_REGULAR};
use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget};
use crate::draw::Font;
use crate::{
fonts::FontRef,
widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget},
};
use chrono::{Datelike, NaiveDateTime};
pub struct Date {
pub struct Date<'a> {
cur_time: NaiveDateTime,
date_cache: Font,
date_cache: Font<'a>,
size: f32,
}
impl Date {
pub fn new(time: NaiveDateTime, size: f32) -> Box<Date> {
let mut date_cache = Font::new(&ROBOTO_REGULAR, size);
impl<'a> Date<'a> {
pub fn new(time: NaiveDateTime, font: FontRef, size: f32) -> Box<Date> {
let mut date_cache = Font::new(font, size);
date_cache
.add_str_to_cache("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,/ ");
@@ -24,7 +27,7 @@ impl Date {
}
}
impl Widget for Date {
impl<'a> Widget for Date<'a> {
fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {}
fn leave(&mut self) {}
+11 -7
View File
@@ -2,8 +2,11 @@ use crate::buffer::Buffer;
use crate::cmd::Cmd;
use crate::color::Color;
use crate::desktop::{load_desktop_files, Desktop};
use crate::draw::{Font, ROBOTO_REGULAR};
use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget};
use crate::draw::Font;
use crate::{
fonts::FontRef,
widget::{DrawContext, DrawReport, KeyState, ModifiersState, WaitContext, Widget},
};
use std::cell::RefCell;
use std::cmp::Ordering;
@@ -14,7 +17,7 @@ use std::sync::mpsc::Sender;
use fuzzy_matcher::skim::{fuzzy_indices, fuzzy_match};
use smithay_client_toolkit::keyboard::keysyms;
pub struct Launcher {
pub struct Launcher<'a> {
options: Vec<Desktop>,
term_opener: String,
app_opener: String,
@@ -23,15 +26,16 @@ pub struct Launcher {
input: String,
result: Option<String>,
offset: usize,
font: RefCell<Font>,
font: RefCell<Font<'a>>,
font_size: u32,
length: u32,
dirty: bool,
tx: Sender<Cmd>,
}
impl Launcher {
impl<'a> Launcher<'a> {
pub fn new(
font: FontRef,
font_size: f32,
length: u32,
listener: Sender<Cmd>,
@@ -48,7 +52,7 @@ impl Launcher {
input: "".to_string(),
result: None,
offset: 0,
font: RefCell::new(Font::new(&ROBOTO_REGULAR, font_size)),
font: RefCell::new(Font::new(font, font_size)),
font_size: font_size as u32,
length,
dirty: true,
@@ -244,7 +248,7 @@ impl Matcher {
}
}
impl Widget for Launcher {
impl<'a> Widget for Launcher<'a> {
fn wait(&mut self, _: &mut WaitContext) {}
fn enter(&mut self) {}
fn leave(&mut self) {