More better
This commit is contained in:
+21
-21
@@ -199,15 +199,16 @@ impl<'a> BufferView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subdimensions(
|
||||
&mut self,
|
||||
subdimensions: (u32, u32, u32, u32),
|
||||
) -> BufferView {
|
||||
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> BufferView {
|
||||
let bounds = self.get_bounds();
|
||||
if cfg!(debug_assertions) && (subdimensions.0 + subdimensions.2 > bounds.2
|
||||
|| subdimensions.1 + subdimensions.3 > bounds.3)
|
||||
if cfg!(debug_assertions)
|
||||
&& (subdimensions.0 + subdimensions.2 > bounds.2
|
||||
|| subdimensions.1 + subdimensions.3 > bounds.3)
|
||||
{
|
||||
panic!("cannot create subdimensions larger than buffer: {:?} > {:?}", subdimensions, bounds);
|
||||
panic!(
|
||||
"cannot create subdimensions larger than buffer: {:?} > {:?}",
|
||||
subdimensions, bounds
|
||||
);
|
||||
}
|
||||
|
||||
BufferView {
|
||||
@@ -229,7 +230,10 @@ impl<'a> BufferView<'a> {
|
||||
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView {
|
||||
let bounds = self.get_bounds();
|
||||
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
|
||||
panic!("cannot create offset outside buffer: {:?} > {:?}", offset, bounds);
|
||||
panic!(
|
||||
"cannot create offset outside buffer: {:?} > {:?}",
|
||||
offset, bounds
|
||||
);
|
||||
}
|
||||
|
||||
BufferView {
|
||||
@@ -268,19 +272,15 @@ impl<'a> BufferView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put(&mut self, pos: (u32, u32), c: Color) {
|
||||
let true_pos = if let Some(subdim) = self.subdimensions {
|
||||
if cfg!(debug_assertions) && (pos.0 >= subdim.2 || pos.1 >= subdim.3) {
|
||||
panic!("put({:?}) is not within subdimensions of buffer ({:?})", pos, subdim);
|
||||
}
|
||||
(pos.0 + subdim.0, pos.1 + subdim.1)
|
||||
} else {
|
||||
if cfg!(debug_assertions) && (pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1) {
|
||||
panic!("put({:?}) is not within dimensions of buffer ({:?})", pos, self.dimensions);
|
||||
}
|
||||
pos
|
||||
};
|
||||
#[inline]
|
||||
pub fn put_raw(&mut self, pos: (u32, u32), c: Color) {
|
||||
self.view[(pos.0 + pos.1 * self.dimensions.0) as usize] = c.0
|
||||
}
|
||||
|
||||
self.view[(true_pos.0 + (true_pos.1 * self.dimensions.0)) as usize] = c.0;
|
||||
#[inline]
|
||||
pub fn put_line_raw(&mut self, pos: (u32, u32), len: u32, c: Color) {
|
||||
let start = (pos.0 + (pos.1 * self.dimensions.0)) as usize;
|
||||
let len = len as usize;
|
||||
self.view[start..start + len].fill(c.0);
|
||||
}
|
||||
}
|
||||
|
||||
+24
-95
@@ -1,113 +1,42 @@
|
||||
//use serde::{Deserialize, Serialize};
|
||||
/*
|
||||
//#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
|
||||
pub struct Color {
|
||||
red: f32,
|
||||
green: f32,
|
||||
blue: f32,
|
||||
opacity: f32,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(red: f32, green: f32, blue: f32, opacity: f32) -> Color {
|
||||
let (red, green, blue, opacity) = clamp(red, green, blue, opacity);
|
||||
Color {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
opacity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blend(&self, other: &Color, ratio: f32) -> Color {
|
||||
let ratio = clamp_f32(ratio, 0.0, 1.0);
|
||||
|
||||
Color {
|
||||
red: blend_f32(self.red, other.red, ratio),
|
||||
green: blend_f32(self.green, other.green, ratio),
|
||||
blue: blend_f32(self.blue, other.blue, ratio),
|
||||
opacity: blend_f32(self.opacity, other.opacity, ratio),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_argb8888(&self) -> u32 {
|
||||
((255.0 * self.opacity) as u32 & 0xFF) << 24
|
||||
| ((255.0 * self.red) as u32 & 0xFF) << 16
|
||||
| ((255.0 * self.green) as u32 & 0xFF) << 8
|
||||
| ((255.0 * self.blue) as u32 & 0xFF)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_integer(&self) -> IntegerColor {
|
||||
IntegerColor(self.as_argb8888())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp(r: f32, g: f32, b: f32, o: f32) -> (f32, f32, f32, f32) {
|
||||
clamp_naive(r, g, b, o)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp_naive(r: f32, g: f32, b: f32, o: f32) -> (f32, f32, f32, f32) {
|
||||
(
|
||||
clamp_f32(r, 0.0, 1.0),
|
||||
clamp_f32(g, 0.0, 1.0),
|
||||
clamp_f32(b, 0.0, 1.0),
|
||||
clamp_f32(o, 0.0, 1.0),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp_f32(v: f32, a: f32, b: f32) -> f32 {
|
||||
if v > b {
|
||||
b
|
||||
} else if v < a {
|
||||
a
|
||||
} else {
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn blend_f32(a: f32, b: f32, r: f32) -> f32 {
|
||||
a + ((b - a) * r)
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Color(pub u32);
|
||||
|
||||
impl Color {
|
||||
pub const WHITE: Color = Color(0xFFFFFFFF);
|
||||
pub const GREY50: Color = Color(0xFF7F7F7F);
|
||||
pub const GREY75: Color = Color(0xFFBFBFBF);
|
||||
pub const GREY80: Color = Color(0xFFCCCCCC);
|
||||
pub const RED: Color = Color(0xFFFF0000);
|
||||
pub const YELLOW: Color = Color(0xFFFFFF00);
|
||||
pub const LIGHTGREEN: Color = Color(0xFF7FFF7F);
|
||||
pub const LIGHTRED: Color = Color(0xFFFF7F7F);
|
||||
pub const WHITE: Color = Color(0xFFFFFFFF);
|
||||
pub const GREY35: Color = Color(0xFF595959);
|
||||
pub const GREY50: Color = Color(0xFF7F7F7F);
|
||||
pub const GREY75: Color = Color(0xFFBFBFBF);
|
||||
pub const GREY80: Color = Color(0xFFCCCCCC);
|
||||
pub const RED: Color = Color(0xFFFF0000);
|
||||
pub const YELLOW: Color = Color(0xFFFFFF00);
|
||||
pub const LIGHTGREEN: Color = Color(0xFF7FFF7F);
|
||||
pub const LIGHTORANGE: Color = Color(0xFFFFBF00);
|
||||
pub const DARKORANGE: Color = Color(0xFFFF7F00);
|
||||
pub const BUFF: Color = Color(0xFFFFBF7F);
|
||||
pub const DARKORANGE: Color = Color(0xFFFF7F00);
|
||||
pub const BUFF: Color = Color(0xFFFFBF7F);
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn new(red: u8, green: u8, blue: u8, opacity: u8) -> Color {
|
||||
Color((opacity as u32) << 24 | (red as u32) << 16 | (green as u32) << 8 | (blue as u32))
|
||||
}
|
||||
|
||||
fn red(self) -> u8 {((self.0 >> 16) & 0xFF) as u8 }
|
||||
fn green(self) -> u8 {((self.0 >> 8) & 0xFF) as u8 }
|
||||
fn blue(self) -> u8 {(self.0 & 0xFF) as u8 }
|
||||
fn red(self) -> u8 {
|
||||
((self.0 >> 16) & 0xFF) as u8
|
||||
}
|
||||
fn green(self) -> u8 {
|
||||
((self.0 >> 8) & 0xFF) as u8
|
||||
}
|
||||
fn blue(self) -> u8 {
|
||||
(self.0 & 0xFF) as u8
|
||||
}
|
||||
|
||||
pub fn alpha(self, alpha: f32) -> Color {
|
||||
unsafe {
|
||||
Color(
|
||||
(255. * alpha).to_int_unchecked::<u32>() << 24 |
|
||||
(self.red() as f32 * alpha).to_int_unchecked::<u32>() << 16 |
|
||||
(self.green() as f32 * alpha).to_int_unchecked::<u32>() << 8 |
|
||||
(self.blue() as f32 * alpha).to_int_unchecked::<u32>())
|
||||
(255. * alpha).to_int_unchecked::<u32>() << 24
|
||||
| (self.red() as f32 * alpha).to_int_unchecked::<u32>() << 16
|
||||
| (self.green() as f32 * alpha).to_int_unchecked::<u32>() << 8
|
||||
| (self.blue() as f32 * alpha).to_int_unchecked::<u32>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-18
@@ -21,7 +21,6 @@ impl CachedGlyph {
|
||||
|
||||
if let Some(bounding_box) = glyph.pixel_bounding_box() {
|
||||
let origin = (bounding_box.min.x, bounding_box.min.y);
|
||||
|
||||
let dimensions = (
|
||||
(bounding_box.max.x - bounding_box.min.x) as u32,
|
||||
(bounding_box.max.y - bounding_box.min.y) as u32,
|
||||
@@ -50,13 +49,15 @@ impl CachedGlyph {
|
||||
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), c: Color) {
|
||||
let mut x = 0;
|
||||
let mut y = 0;
|
||||
let bounds = buf.get_bounds();
|
||||
let offset = (bounds.0 as i32, bounds.1 as i32);
|
||||
for v in &self.render {
|
||||
let _ = buf.put(
|
||||
buf.put_raw(
|
||||
(
|
||||
(x + pos.0 + self.origin.0) as u32,
|
||||
(y + pos.1 + self.origin.1) as u32,
|
||||
(x + pos.0 + self.origin.0 + offset.0) as u32,
|
||||
(y + pos.1 + self.origin.1 + offset.1) as u32,
|
||||
),
|
||||
c.alpha(*v)
|
||||
c.alpha(*v),
|
||||
);
|
||||
|
||||
if x == self.dimensions.0 as i32 - 1 {
|
||||
@@ -180,8 +181,9 @@ impl<'a> Font<'a> {
|
||||
height: u32,
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
// draw cursor
|
||||
for i in 1..height {
|
||||
buf.put((offset, i), c);
|
||||
let bounds = buf.get_bounds();
|
||||
for i in bounds.1 + 1..height + bounds.1 {
|
||||
buf.put_raw((bounds.0 + offset, i), c);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -305,13 +307,12 @@ impl<'a> Font<'a> {
|
||||
}
|
||||
|
||||
pub fn draw_box(buf: &mut BufferView, c: Color, dim: (u32, u32)) -> Result<(), ::std::io::Error> {
|
||||
for x in 0..dim.0 {
|
||||
buf.put((x, 0), c);
|
||||
buf.put((x, dim.1 - 1), c);
|
||||
}
|
||||
for y in 0..dim.1 {
|
||||
buf.put((0, y), c);
|
||||
buf.put((dim.0 - 1, y), c);
|
||||
let bounds = buf.get_bounds();
|
||||
buf.put_line_raw((bounds.0, bounds.1), dim.0, c);
|
||||
buf.put_line_raw((bounds.0, bounds.1 + dim.1 - 1), dim.0, c);
|
||||
for y in bounds.1..dim.1 + bounds.1 {
|
||||
buf.put_raw((bounds.0, y), c);
|
||||
buf.put_raw((bounds.0 + dim.0 - 1, y), c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -328,10 +329,9 @@ pub fn draw_bar(
|
||||
if fill_pos > length {
|
||||
fill_pos = length;
|
||||
}
|
||||
for y in 0..height {
|
||||
for x in 0..fill_pos {
|
||||
let _ = buf.put((x, y), color);
|
||||
}
|
||||
let bounds = buf.get_bounds();
|
||||
for y in bounds.1..height + bounds.1 {
|
||||
buf.put_line_raw((bounds.0, y), fill_pos, color);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -58,4 +58,3 @@ impl Events {
|
||||
self.events.drain(..).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-11
@@ -3,15 +3,7 @@
|
||||
use crate::draw;
|
||||
use rusttype::Font;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fs::File,
|
||||
hash,
|
||||
io::Read,
|
||||
mem,
|
||||
path::Path,
|
||||
rc::Rc,
|
||||
thread,
|
||||
cell::RefCell, collections::HashMap, fs::File, hash, io::Read, mem, path::Path, rc::Rc, thread,
|
||||
};
|
||||
|
||||
/// FontRef is used to store Fonts on widgets.
|
||||
@@ -24,7 +16,12 @@ mod fc {
|
||||
/// Given a string, it matches it to a font file and returns its path.
|
||||
pub(crate) fn from_string(name: &str) -> String {
|
||||
let fc = FontConfig::new().unwrap();
|
||||
fc.find(name, None).unwrap().path.to_str().unwrap().to_string()
|
||||
fc.find(name, None)
|
||||
.unwrap()
|
||||
.path
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +95,8 @@ impl FontMap {
|
||||
match self.required_fonts.get_mut(font_name) {
|
||||
Some(v) => v.1.push((size, preload)),
|
||||
None => {
|
||||
self.required_fonts.insert(font_name, (font_name, vec![(size, preload)]));
|
||||
self.required_fonts
|
||||
.insert(font_name, (font_name, vec![(size, preload)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -45,7 +45,10 @@ pub struct Keyboard {
|
||||
|
||||
impl Keyboard {
|
||||
pub fn new() -> Keyboard {
|
||||
Keyboard { state: None, fd: None, }
|
||||
Keyboard {
|
||||
state: None,
|
||||
fd: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keymap(&mut self, format: WEnum<wl_keyboard::KeymapFormat>, fd: OwnedFd, size: u32) {
|
||||
|
||||
+39
-29
@@ -1,12 +1,12 @@
|
||||
mod buffer;
|
||||
mod color;
|
||||
mod draw;
|
||||
mod event;
|
||||
mod fonts;
|
||||
mod keyboard;
|
||||
mod state;
|
||||
mod utils;
|
||||
mod widgets;
|
||||
mod event;
|
||||
|
||||
use wayland_client::{Connection, QueueHandle, WaylandSource};
|
||||
|
||||
@@ -17,19 +17,15 @@ use calloop::{
|
||||
use chrono::{Duration, Local, Timelike};
|
||||
|
||||
use buffer::BufferView;
|
||||
use fonts::{FontMap, MaybeFontMap};
|
||||
use state::{State, OperationMode};
|
||||
use event::{Event, Events};
|
||||
use fonts::{FontMap, MaybeFontMap};
|
||||
use state::{OperationMode, State};
|
||||
use widgets::{
|
||||
PulseAudio, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget, Layout,
|
||||
Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||
Interface, InvertedHorizontalLayout, Layout, Line, Margin, PulseAudio, VerticalLayout, Widget,
|
||||
};
|
||||
|
||||
use std::{
|
||||
env,
|
||||
rc::Rc,
|
||||
thread
|
||||
};
|
||||
use std::{env, rc::Rc, thread};
|
||||
|
||||
enum UIVersion {
|
||||
V1,
|
||||
@@ -52,7 +48,7 @@ fn main() {
|
||||
(Some(w), Some(h)) => mode = OperationMode::LayerSurface((w, h)),
|
||||
_ => panic!("invalid arguments"),
|
||||
}
|
||||
},
|
||||
}
|
||||
Some(ref s) if s == "xdg_shell" => mode = OperationMode::XdgToplevel,
|
||||
Some(ref s) if s == "v1" => version = UIVersion::V1,
|
||||
Some(ref s) if s == "v2" => version = UIVersion::V2,
|
||||
@@ -120,27 +116,31 @@ fn main() {
|
||||
let mut fm = FontMap::new();
|
||||
|
||||
// TODO: Cache in a file
|
||||
fm.add_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf".to_string());
|
||||
fm.add_font_path("monospace", "/usr/share/fonts/noto/NotoSansMono-Regular.ttf".to_string());
|
||||
fm.add_font_path(
|
||||
"sans",
|
||||
"/usr/share/fonts/noto/NotoSans-Regular.ttf".to_string(),
|
||||
);
|
||||
fm.add_font_path(
|
||||
"monospace",
|
||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf".to_string(),
|
||||
);
|
||||
|
||||
let (widgets, layout): (Vec<Box<dyn Widget>>, Rc<Box<dyn Layout>>) = match version {
|
||||
UIVersion::V1 => {
|
||||
let clock = Box::new(Clock::new(&mut fm, "sans", 256.));
|
||||
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 18.0, -1, 1));
|
||||
let calendar = Box::new(Calendar::new(&mut fm, "monospace", "sans", 36.0, 3, 1));
|
||||
let date = Box::new(Date::new(&mut fm, "sans", 48.));
|
||||
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
|
||||
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
|
||||
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.));
|
||||
|
||||
let v: Vec<Box<dyn Widget>> = vec![clock, date, battery, backlight, audio, calendar, launcher];
|
||||
let v: Vec<Box<dyn Widget>> =
|
||||
vec![clock, date, battery, backlight, audio, calendar, launcher];
|
||||
let l = Rc::new(Margin::new(
|
||||
VerticalLayout::new(vec![
|
||||
HorizontalLayout::new(vec![
|
||||
VerticalLayout::new(vec![
|
||||
IndexedLayout::new(1),
|
||||
IndexedLayout::new(0),
|
||||
]),
|
||||
VerticalLayout::new(vec![IndexedLayout::new(1), IndexedLayout::new(0)]),
|
||||
Margin::new(
|
||||
VerticalLayout::new(vec![
|
||||
Margin::new(IndexedLayout::new(2), (0, 0, 0, 8)),
|
||||
@@ -152,20 +152,23 @@ fn main() {
|
||||
]),
|
||||
IndexedLayout::new(5),
|
||||
IndexedLayout::new(6),
|
||||
]), (20, 20, 20, 20))
|
||||
);
|
||||
]),
|
||||
(20, 20, 20, 20),
|
||||
));
|
||||
(v, l)
|
||||
}
|
||||
UIVersion::V2 => {
|
||||
let clock = Box::new(Clock::new(&mut fm, "sans", 128.));
|
||||
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 12.0, 1, -1));
|
||||
let calendar = Box::new(Calendar::new(&mut fm, "monospace", "sans", 24.0, 1, -1));
|
||||
let date = Box::new(Date::new(&mut fm, "sans", 48.));
|
||||
let line = Box::new(Line::new(1));
|
||||
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
|
||||
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
|
||||
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.));
|
||||
let v: Vec<Box<dyn Widget>> = vec![clock, date, battery, backlight, audio, line, calendar, launcher];
|
||||
let v: Vec<Box<dyn Widget>> = vec![
|
||||
clock, date, battery, backlight, audio, line, calendar, launcher,
|
||||
];
|
||||
let l = Rc::new(VerticalLayout::new(vec![
|
||||
HorizontalLayout::new(vec![
|
||||
IndexedLayout::new(0),
|
||||
@@ -186,11 +189,18 @@ fn main() {
|
||||
let font_thread = thread::Builder::new()
|
||||
.name("fontloader".to_string())
|
||||
.spawn(move || {
|
||||
fm.load_fonts();
|
||||
fm
|
||||
}).unwrap();
|
||||
fm.load_fonts();
|
||||
fm
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut state = State::new(mode, widgets, layout, MaybeFontMap::Waiting(font_thread), events);
|
||||
let mut state = State::new(
|
||||
mode,
|
||||
widgets,
|
||||
layout,
|
||||
MaybeFontMap::Waiting(font_thread),
|
||||
events,
|
||||
);
|
||||
|
||||
let mut damage = Vec::new();
|
||||
for _ in 0..state.widgets.len() {
|
||||
|
||||
+112
-64
@@ -1,43 +1,39 @@
|
||||
use std::{
|
||||
cmp::max,
|
||||
default::Default,
|
||||
env,
|
||||
process::exit,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
default::Default,
|
||||
};
|
||||
|
||||
use wayland_client::{
|
||||
protocol::{
|
||||
wl_buffer, wl_compositor, wl_subcompositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||
wl_surface, wl_subsurface, wl_pointer,
|
||||
wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm,
|
||||
wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface,
|
||||
},
|
||||
Connection, Dispatch, QueueHandle, WEnum,
|
||||
};
|
||||
|
||||
use wayland_protocols::{
|
||||
wp::{
|
||||
single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1,
|
||||
viewporter::client::{wp_viewport, wp_viewporter},
|
||||
},
|
||||
xdg::{
|
||||
activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1},
|
||||
shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base},
|
||||
},
|
||||
wp::{
|
||||
single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1,
|
||||
viewporter::client::{
|
||||
wp_viewport,
|
||||
wp_viewporter,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::{
|
||||
zwlr_layer_shell_v1, zwlr_layer_surface_v1,
|
||||
};
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
|
||||
|
||||
use crate::{
|
||||
buffer::BufferManager,
|
||||
event::{Event, Events, PointerButton, PointerEvent},
|
||||
fonts::{FontMap, MaybeFontMap},
|
||||
keyboard::Keyboard,
|
||||
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
||||
event::{Event, Events, PointerEvent, PointerButton},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -127,7 +123,10 @@ impl State {
|
||||
Ok(token) => token,
|
||||
Err(_) => return,
|
||||
};
|
||||
match (&self.main_surface.wl_surface, &self.protocols.xdg_activation) {
|
||||
match (
|
||||
&self.main_surface.wl_surface,
|
||||
&self.protocols.xdg_activation,
|
||||
) {
|
||||
(Some(surface), Some(activation)) => {
|
||||
activation.activate(key, surface);
|
||||
let activation_token = activation.get_activation_token(qh, ());
|
||||
@@ -148,6 +147,10 @@ impl WidgetUpdater for State {
|
||||
) -> Geometry {
|
||||
self.widgets[idx].geometry_update(fonts, geometry)
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, idx: usize, fonts: &mut FontMap) -> Geometry {
|
||||
self.widgets[idx].minimum_size(fonts)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||
@@ -182,30 +185,34 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||
let subsurface = subcompositor.get_subsurface(child, parent, qh, ());
|
||||
subsurface.place_below(parent);
|
||||
state.bg_surface.subsurface = Some(subsurface);
|
||||
},
|
||||
}
|
||||
_ => todo!("handle early subcompositor creation"),
|
||||
}
|
||||
}
|
||||
"wl_shm" => {
|
||||
state.protocols.wl_shm = Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
|
||||
state.protocols.wl_shm =
|
||||
Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
|
||||
}
|
||||
"wl_seat" => {
|
||||
registry.bind::<wl_seat::WlSeat, _, _>(name, 8, qh, ());
|
||||
}
|
||||
"xdg_wm_base" => if let OperationMode::XdgToplevel = state.mode {
|
||||
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 2, qh, ());
|
||||
"xdg_wm_base" => {
|
||||
if let OperationMode::XdgToplevel = state.mode {
|
||||
let wm_base =
|
||||
registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 2, qh, ());
|
||||
|
||||
match &state.main_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let xdg_surface = wm_base.get_xdg_surface(surface, qh, ());
|
||||
let toplevel = xdg_surface.get_toplevel(qh, ());
|
||||
toplevel.set_title("wldash".into());
|
||||
match &state.main_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let xdg_surface = wm_base.get_xdg_surface(surface, qh, ());
|
||||
let toplevel = xdg_surface.get_toplevel(qh, ());
|
||||
toplevel.set_title("wldash".into());
|
||||
|
||||
surface.commit();
|
||||
surface.commit();
|
||||
|
||||
state.main_surface.xdg_surface = Some((xdg_surface, toplevel));
|
||||
state.main_surface.xdg_surface = Some((xdg_surface, toplevel));
|
||||
}
|
||||
_ => todo!("handle early xdg_shell creation"),
|
||||
}
|
||||
_ => todo!("handle early xdg_shell creation"),
|
||||
}
|
||||
}
|
||||
"xdg_activation_v1" => {
|
||||
@@ -214,41 +221,63 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||
);
|
||||
state.activate(qh);
|
||||
}
|
||||
"zwlr_layer_shell_v1" => if let OperationMode::LayerSurface(size) = state.mode {
|
||||
let layer_shell = registry.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ());
|
||||
match &state.main_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let layer_surface = layer_shell.get_layer_surface(surface, None, zwlr_layer_shell_v1::Layer::Top, "launcher".to_string(), qh, ());
|
||||
layer_surface.set_keyboard_interactivity(zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive);
|
||||
layer_surface.set_size(size.0, size.1);
|
||||
"zwlr_layer_shell_v1" => {
|
||||
if let OperationMode::LayerSurface(size) = state.mode {
|
||||
let layer_shell = registry
|
||||
.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ());
|
||||
state.fonts.resolve();
|
||||
let fonts = state.fonts.unwrap();
|
||||
let layout = state.layout.clone();
|
||||
let min_size = layout.minimum_size(&mut fonts.borrow_mut(), state);
|
||||
match &state.main_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let layer_surface = layer_shell.get_layer_surface(
|
||||
surface,
|
||||
None,
|
||||
zwlr_layer_shell_v1::Layer::Top,
|
||||
"launcher".to_string(),
|
||||
qh,
|
||||
(),
|
||||
);
|
||||
layer_surface.set_keyboard_interactivity(
|
||||
zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive,
|
||||
);
|
||||
layer_surface.set_size(
|
||||
max(size.0, min_size.width),
|
||||
max(size.1, min_size.height),
|
||||
);
|
||||
|
||||
surface.commit();
|
||||
state.main_surface.layer_surface = Some(layer_surface);
|
||||
surface.commit();
|
||||
state.main_surface.layer_surface = Some(layer_surface);
|
||||
}
|
||||
_ => todo!("handle early layer_shell creation"),
|
||||
}
|
||||
_ => todo!("handle early layer_shell creation"),
|
||||
}
|
||||
},
|
||||
}
|
||||
"wp_viewporter" => {
|
||||
let viewporter = registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ());
|
||||
let viewporter =
|
||||
registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ());
|
||||
match &state.bg_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
state.bg_surface.viewport = Some(viewporter.get_viewport(surface, qh, ()));
|
||||
},
|
||||
state.bg_surface.viewport =
|
||||
Some(viewporter.get_viewport(surface, qh, ()));
|
||||
}
|
||||
_ => todo!("handle early viewporter creation"),
|
||||
}
|
||||
state.protocols.viewporter = Some(viewporter);
|
||||
},
|
||||
}
|
||||
"wp_single_pixel_buffer_manager_v1" => {
|
||||
let singlepixel = registry.bind::<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, _, _>(name, 1, qh, ());
|
||||
match &state.bg_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let buffer = singlepixel.create_u32_rgba_buffer(0, 0, 0, 0xFFFFFFFF, qh, ());
|
||||
let buffer =
|
||||
singlepixel.create_u32_rgba_buffer(0, 0, 0, 0xFFFFFFFF, qh, ());
|
||||
surface.attach(Some(&buffer), 0, 0);
|
||||
surface.damage_buffer(0, 0, 1, 1);
|
||||
},
|
||||
}
|
||||
_ => todo!("handle early single_pixel_buffer creation"),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +381,8 @@ impl Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, ()> for State {
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
|
||||
@@ -364,7 +394,12 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let zwlr_layer_surface_v1::Event::Configure { serial, width, height } = event {
|
||||
if let zwlr_layer_surface_v1::Event::Configure {
|
||||
serial,
|
||||
width,
|
||||
height,
|
||||
} = event
|
||||
{
|
||||
if (width, height) == (0, 0) {
|
||||
return;
|
||||
}
|
||||
@@ -397,7 +432,7 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
|
||||
(Some(surface), Some(viewport)) => {
|
||||
viewport.set_destination(dim.0, dim.1);
|
||||
surface.commit();
|
||||
},
|
||||
}
|
||||
_ => todo!("handle early layer shell creation"),
|
||||
}
|
||||
}
|
||||
@@ -577,20 +612,30 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
match event {
|
||||
wl_pointer::Event::Enter { surface_x, surface_y, .. } => {
|
||||
wl_pointer::Event::Enter {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
state.pointer = Some((surface_x, surface_y));
|
||||
},
|
||||
wl_pointer::Event::Motion { surface_x, surface_y, .. } => {
|
||||
}
|
||||
wl_pointer::Event::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
state.pointer = Some((surface_x, surface_y));
|
||||
},
|
||||
wl_pointer::Event::Leave { .. } => {
|
||||
state.pointer = None
|
||||
},
|
||||
wl_pointer::Event::Axis { axis, value, .. } => match state.pointer {
|
||||
}
|
||||
wl_pointer::Event::Leave { .. } => state.pointer = None,
|
||||
wl_pointer::Event::Axis { axis, value, .. } => match state.pointer {
|
||||
Some((x, y)) => {
|
||||
let axis = match axis {
|
||||
WEnum::Value(wl_pointer::Axis::VerticalScroll) => PointerButton::ScrollVertical(value),
|
||||
WEnum::Value(wl_pointer::Axis::HorizontalScroll) => PointerButton::ScrollHorizontal(value),
|
||||
WEnum::Value(wl_pointer::Axis::VerticalScroll) => {
|
||||
PointerButton::ScrollVertical(value)
|
||||
}
|
||||
WEnum::Value(wl_pointer::Axis::HorizontalScroll) => {
|
||||
PointerButton::ScrollHorizontal(value)
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
let pos = (x as u32, y as u32);
|
||||
@@ -598,7 +643,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
let geo = widget.geometry();
|
||||
if geo.contains(pos) {
|
||||
let pos = (pos.0 - geo.x, pos.1 - geo.y);
|
||||
let ev = Event::PointerEvent(PointerEvent{
|
||||
let ev = Event::PointerEvent(PointerEvent {
|
||||
button: axis,
|
||||
pos: pos,
|
||||
});
|
||||
@@ -607,10 +652,14 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
wl_pointer::Event::Button { button, state: button_state, .. } => match (button, button_state, state.pointer) {
|
||||
wl_pointer::Event::Button {
|
||||
button,
|
||||
state: button_state,
|
||||
..
|
||||
} => match (button, button_state, state.pointer) {
|
||||
(button, WEnum::Value(wl_pointer::ButtonState::Pressed), Some((x, y))) => {
|
||||
let button = match button {
|
||||
BTN_LEFT => PointerButton::Left,
|
||||
@@ -622,9 +671,8 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
for widget in state.widgets.iter_mut() {
|
||||
let geo = widget.geometry();
|
||||
if geo.contains(pos) {
|
||||
|
||||
let pos = (pos.0 - geo.x, pos.1 - geo.y);
|
||||
let ev = Event::PointerEvent(PointerEvent{
|
||||
let ev = Event::PointerEvent(PointerEvent {
|
||||
button: button,
|
||||
pos: pos,
|
||||
});
|
||||
@@ -633,7 +681,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
draw::{draw_bar, draw_box},
|
||||
event::{Event, PointerButton},
|
||||
fonts::FontMap,
|
||||
widgets::{Geometry, Widget},
|
||||
event::{Event, PointerButton},
|
||||
};
|
||||
|
||||
pub trait BarWidgetImpl {
|
||||
@@ -27,7 +27,12 @@ pub struct BarWidget {
|
||||
}
|
||||
|
||||
impl BarWidget {
|
||||
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||
pub fn new(
|
||||
inner_widget: Box<dyn BarWidgetImpl>,
|
||||
fm: &mut FontMap,
|
||||
font: &'static str,
|
||||
size: f32,
|
||||
) -> BarWidget {
|
||||
fm.queue_font(font, size, inner_widget.name());
|
||||
BarWidget {
|
||||
geometry: Default::default(),
|
||||
@@ -51,8 +56,7 @@ impl Widget for BarWidget {
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
let fg = Color::WHITE;
|
||||
|
||||
font.draw_text(view, fg, self.inner_widget.name())
|
||||
.unwrap();
|
||||
font.draw_text(view, fg, self.inner_widget.name()).unwrap();
|
||||
let size = self.size.ceil() as u32;
|
||||
let bar_offset = 4 * size;
|
||||
let val = self.inner_widget.value();
|
||||
@@ -91,6 +95,15 @@ impl Widget for BarWidget {
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: self.size.ceil() as u32 * 6,
|
||||
height: self.size.ceil() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&mut self, event: &Event) {
|
||||
match event {
|
||||
Event::PointerEvent(ev) => {
|
||||
@@ -99,9 +112,8 @@ impl Widget for BarWidget {
|
||||
let val = (ev.pos.0 - offset) as f32 / (self.geometry.width - offset) as f32;
|
||||
self.inner_widget.click(val, ev.button);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+29
-25
@@ -11,18 +11,33 @@ use dbus::blocking::{
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
event::{Event, Events},
|
||||
fonts::FontMap,
|
||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||
};
|
||||
|
||||
enum UpowerBatteryState {
|
||||
Unknown,
|
||||
Charging,
|
||||
Discharging,
|
||||
Empty,
|
||||
Full,
|
||||
NotCharging,
|
||||
Unknown,
|
||||
FullyCharged,
|
||||
PendingCharge,
|
||||
PendingDischarge,
|
||||
}
|
||||
|
||||
impl UpowerBatteryState {
|
||||
fn from_dbus(val: u64) -> UpowerBatteryState {
|
||||
match val {
|
||||
1 => UpowerBatteryState::Charging,
|
||||
2 => UpowerBatteryState::Discharging,
|
||||
3 => UpowerBatteryState::Empty,
|
||||
4 => UpowerBatteryState::FullyCharged,
|
||||
5 => UpowerBatteryState::PendingCharge,
|
||||
6 => UpowerBatteryState::PendingDischarge,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerBattery {
|
||||
@@ -53,15 +68,7 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
||||
{
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.value = capacity as f32 / 100.;
|
||||
inner.state = match state {
|
||||
1 => UpowerBatteryState::Charging,
|
||||
2 => UpowerBatteryState::Discharging,
|
||||
3 => UpowerBatteryState::Empty,
|
||||
4 => UpowerBatteryState::Full,
|
||||
5 => UpowerBatteryState::NotCharging,
|
||||
6 => UpowerBatteryState::Discharging,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
}
|
||||
inner.state = UpowerBatteryState::from_dbus(state as u64);
|
||||
}
|
||||
|
||||
proxy
|
||||
@@ -76,15 +83,8 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
||||
for (key, value) in c.changed_properties {
|
||||
match key.as_str() {
|
||||
"State" => {
|
||||
inner.state = match value.0.as_u64().unwrap() {
|
||||
1 => UpowerBatteryState::Charging,
|
||||
2 => UpowerBatteryState::Discharging,
|
||||
3 => UpowerBatteryState::Empty,
|
||||
4 => UpowerBatteryState::Full,
|
||||
5 => UpowerBatteryState::NotCharging,
|
||||
6 => UpowerBatteryState::Discharging,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
};
|
||||
inner.state =
|
||||
UpowerBatteryState::from_dbus(value.0.as_u64().unwrap());
|
||||
inner.dirty = true;
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
@@ -115,7 +115,12 @@ pub struct Battery {
|
||||
}
|
||||
|
||||
impl Battery {
|
||||
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||
pub fn new(
|
||||
events: Arc<Mutex<Events>>,
|
||||
fm: &mut FontMap,
|
||||
font: &'static str,
|
||||
size: f32,
|
||||
) -> BarWidget {
|
||||
let battery = Battery {
|
||||
inner: Arc::new(Mutex::new(InnerBattery {
|
||||
value: 0.,
|
||||
@@ -143,8 +148,7 @@ impl BarWidgetImpl for Battery {
|
||||
fn color(&self) -> Color {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
match inner.state {
|
||||
UpowerBatteryState::Charging | UpowerBatteryState::Full => Color::LIGHTGREEN,
|
||||
UpowerBatteryState::NotCharging => Color::LIGHTRED,
|
||||
UpowerBatteryState::Charging | UpowerBatteryState::FullyCharged => Color::LIGHTGREEN,
|
||||
_ if inner.value > 0.25 => Color::WHITE,
|
||||
_ if inner.value > 0.1 => Color::DARKORANGE,
|
||||
_ => Color::RED,
|
||||
|
||||
+163
-108
@@ -3,8 +3,8 @@ use std::default::Default;
|
||||
use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
event::Event,
|
||||
fonts::FontMap,
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ use chrono::{Datelike, Local, NaiveDate};
|
||||
|
||||
pub struct Calendar {
|
||||
font: &'static str,
|
||||
month_font: &'static str,
|
||||
sections_x: i32,
|
||||
sections_y: i32,
|
||||
shown_sections_x: u32,
|
||||
@@ -19,22 +20,35 @@ pub struct Calendar {
|
||||
size: f32,
|
||||
dirty: bool,
|
||||
geometry: Geometry,
|
||||
year_width: u32,
|
||||
date_width: u32,
|
||||
day_width: u32,
|
||||
}
|
||||
|
||||
const DAY_FACTOR: f32 = 1.;
|
||||
const YEAR_FACTOR: f32 = 1.5;
|
||||
const MONTH_FACTOR: f32 = 2.;
|
||||
const DATE_FACTOR: f32 = 2.;
|
||||
const LINE_HEIGHT: f32 = 1.8;
|
||||
const DAY_FACTOR: f32 = 0.6;
|
||||
const YEAR_FACTOR: f32 = 0.75;
|
||||
const MONTH_FACTOR: f32 = 1.25;
|
||||
const DATE_FACTOR: f32 = 1.;
|
||||
|
||||
const LINE_HEIGHT: f32 = 0.85;
|
||||
|
||||
impl Calendar {
|
||||
pub fn new(fm: &mut FontMap, font: &'static str, size: f32, sections_x: i32, sections_y: i32) -> Calendar {
|
||||
fm.queue_font(font, size, "ADEFHIMNORSTUW");
|
||||
fm.queue_font(font, size * 1.5, "0123456789");
|
||||
fm.queue_font(font, size * 2.0, "0123456789 ADFJMOSabcehgilmnoprstuvy");
|
||||
pub fn new(
|
||||
fm: &mut FontMap,
|
||||
font: &'static str,
|
||||
month_font: &'static str,
|
||||
size: f32,
|
||||
sections_x: i32,
|
||||
sections_y: i32,
|
||||
) -> Calendar {
|
||||
fm.queue_font(font, size * DAY_FACTOR, "ADEFHIMNORSTUW");
|
||||
fm.queue_font(font, size * YEAR_FACTOR, "0123456789");
|
||||
fm.queue_font(font, size * DATE_FACTOR, "0123456789");
|
||||
fm.queue_font(month_font, size * MONTH_FACTOR, "ADFJMOSabcehgilmnoprstuvy");
|
||||
|
||||
Calendar {
|
||||
font,
|
||||
month_font,
|
||||
size,
|
||||
sections_x,
|
||||
sections_y,
|
||||
@@ -42,6 +56,9 @@ impl Calendar {
|
||||
shown_sections_y: 0,
|
||||
dirty: true,
|
||||
geometry: Default::default(),
|
||||
date_width: 0,
|
||||
day_width: 0,
|
||||
year_width: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,39 +69,33 @@ impl Calendar {
|
||||
orig: NaiveDate,
|
||||
mut time: NaiveDate,
|
||||
) {
|
||||
let white = Color::WHITE;
|
||||
let dim = Color::GREY80;
|
||||
let dimmer = Color::GREY75;
|
||||
|
||||
let mut y_off = 1;
|
||||
// TODO: Fix offsets:
|
||||
// - Headline font is not correctly accounted for
|
||||
|
||||
let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
|
||||
//
|
||||
// Draw the week day
|
||||
//
|
||||
let day_offset = (self.date_width - self.day_width) / 2;
|
||||
let date_offset = self.date_width + self.date_width / 2;
|
||||
for idx in 1..8 {
|
||||
let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR);
|
||||
let wk_chr = match idx {
|
||||
1 => "MON",
|
||||
2 => "TUE",
|
||||
3 => "WED",
|
||||
4 => "THU",
|
||||
5 => "FRI",
|
||||
6 => "SAT",
|
||||
7 => "SUN",
|
||||
let (wk_chr, c) = match idx {
|
||||
1 => ("MON", Color::WHITE),
|
||||
2 => ("TUE", Color::WHITE),
|
||||
3 => ("WED", Color::WHITE),
|
||||
4 => ("THU", Color::WHITE),
|
||||
5 => ("FRI", Color::WHITE),
|
||||
6 => ("SAT", Color::GREY80),
|
||||
7 => ("SUN", Color::GREY80),
|
||||
_ => panic!("impossible value"),
|
||||
};
|
||||
|
||||
day_font
|
||||
.draw_text(
|
||||
&mut view
|
||||
.offset((
|
||||
idx * (self.size * 2.5).ceil() as u32 + (self.size / 5.).ceil() as u32,
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * 1.).ceil() as u32,
|
||||
)),
|
||||
white,
|
||||
&mut view.offset((
|
||||
idx * date_offset + day_offset,
|
||||
(self.size * MONTH_FACTOR).ceil() as u32
|
||||
+ (self.size * DAY_FACTOR * 0.2).ceil() as u32,
|
||||
)),
|
||||
c,
|
||||
&wk_chr,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -93,18 +104,7 @@ impl Calendar {
|
||||
//
|
||||
// Draw the month
|
||||
//
|
||||
if time.year() != orig.year() {
|
||||
let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
|
||||
year_font
|
||||
.draw_text(
|
||||
&mut view.offset(((self.size * 17.).ceil() as u32, 0)),
|
||||
dim,
|
||||
&format!("{:}", time.year()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
|
||||
let month_font = fonts.get_font(self.month_font, self.size * MONTH_FACTOR);
|
||||
let month_str = match time.month() {
|
||||
1 => "January",
|
||||
2 => "February",
|
||||
@@ -120,59 +120,62 @@ impl Calendar {
|
||||
12 => "December",
|
||||
_ => panic!("impossible value"),
|
||||
};
|
||||
cal_font
|
||||
.draw_text(&mut view, white, month_str)
|
||||
month_font
|
||||
.draw_text(&mut view, Color::WHITE, month_str)
|
||||
.unwrap();
|
||||
|
||||
let mut done = false;
|
||||
while !done {
|
||||
let mut x_pos = 0;
|
||||
|
||||
//
|
||||
// Find the start of this week
|
||||
//
|
||||
let mut wkday = time.weekday();
|
||||
while wkday != chrono::Weekday::Mon {
|
||||
x_pos += 1;
|
||||
wkday = wkday.pred();
|
||||
}
|
||||
//
|
||||
// Draw the year
|
||||
//
|
||||
if time.year() != orig.year() {
|
||||
let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
|
||||
year_font
|
||||
.draw_text(
|
||||
&mut view.offset((cal_width - self.year_width, 0)),
|
||||
Color::GREY80,
|
||||
&format!("{:}", time.year()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
|
||||
'row: for y_off in 1.. {
|
||||
//
|
||||
// Draw the week number
|
||||
//
|
||||
let wk = time.iso_week();
|
||||
cal_font
|
||||
.draw_text(
|
||||
&mut view
|
||||
.offset((
|
||||
0,
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
dimmer,
|
||||
&mut view.offset((
|
||||
0,
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
Color::GREY75,
|
||||
&format!("{:02}", wk.week()),
|
||||
)
|
||||
.unwrap();
|
||||
x_pos += 1;
|
||||
|
||||
//
|
||||
// Draw the dates
|
||||
//
|
||||
while x_pos < 8 {
|
||||
let x_off = time.weekday().number_from_monday();
|
||||
for x_pos in x_off..8 {
|
||||
let c = if time.day() == orig.day() && time.month() == orig.month() {
|
||||
Color::WHITE
|
||||
} else {
|
||||
} else if x_pos < 6 {
|
||||
Color::GREY50
|
||||
} else {
|
||||
Color::GREY35
|
||||
};
|
||||
|
||||
cal_font
|
||||
.draw_text(
|
||||
&mut view
|
||||
.offset((
|
||||
x_pos * (self.size * 2.5).ceil() as u32,
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
&mut view.offset((
|
||||
x_pos * date_offset,
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
c,
|
||||
&format!("{:02}", time.day()),
|
||||
)
|
||||
@@ -180,14 +183,10 @@ impl Calendar {
|
||||
|
||||
let t = time.with_day(time.day() + 1);
|
||||
if t.is_none() {
|
||||
done = true;
|
||||
break;
|
||||
break 'row;
|
||||
}
|
||||
time = t.unwrap();
|
||||
x_pos += 1;
|
||||
}
|
||||
|
||||
y_off += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,9 +221,10 @@ impl<'a> Widget for Calendar {
|
||||
|
||||
let time = Local::now().naive_local().date();
|
||||
|
||||
let cal_height = (self.size * 16.25).ceil() as u32;
|
||||
let cal_width = (7. * self.size * 2.5 + self.size * 2.).ceil() as u32;
|
||||
let cal_pad = (3. * self.size).ceil() as u32;
|
||||
let cal_height =
|
||||
(self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
|
||||
let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
|
||||
let cal_pad = self.date_width * 2;
|
||||
|
||||
let mut t = time.with_day(1).unwrap();
|
||||
let cals = self.shown_sections_y * self.shown_sections_x;
|
||||
@@ -236,8 +236,7 @@ impl<'a> Widget for Calendar {
|
||||
for idx in 0..self.shown_sections_x {
|
||||
self.draw_month(
|
||||
fonts,
|
||||
&mut view
|
||||
.offset(((cal_width + cal_pad) * idx, (cal_height) * ydx)),
|
||||
&mut view.offset(((cal_width + cal_pad) * idx, cal_height * ydx)),
|
||||
time,
|
||||
t,
|
||||
);
|
||||
@@ -252,35 +251,91 @@ impl<'a> Widget for Calendar {
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||
let cal_width = 7 * (self.size * 2.5).ceil() as u32 + (self.size * 2.).ceil() as u32;
|
||||
let cal_height = (self.size * MONTH_FACTOR).ceil() as u32
|
||||
+ (self.size * LINE_HEIGHT * 8.).ceil() as u32;
|
||||
let cal_pad = (self.size * 3.).ceil() as u32;
|
||||
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||
let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
|
||||
self.year_width = year_font.auto_widest("0123456789").unwrap() * 4;
|
||||
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
|
||||
self.date_width = cal_font.auto_widest("0123456789").unwrap() * 2;
|
||||
let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR);
|
||||
self.day_width = day_font.auto_widest("ADEFHIMNORSTUW").unwrap() * 3;
|
||||
|
||||
let possible_sections_x = geometry.width / (cal_width + cal_pad);
|
||||
let possible_sections_y = geometry.height / cal_height;
|
||||
let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
|
||||
let cal_height =
|
||||
(self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
|
||||
|
||||
let cal_pad = self.date_width * 2;
|
||||
|
||||
if geometry.width < cal_width || geometry.height < cal_height {
|
||||
self.geometry = Default::default();
|
||||
return self.geometry;
|
||||
}
|
||||
|
||||
let possible_sections_x = 1 + (geometry.width - cal_width) / (cal_width + cal_pad);
|
||||
let possible_sections_y = 1 + (geometry.height - cal_height) / cal_height;
|
||||
|
||||
self.shown_sections_x =
|
||||
if self.sections_x > 0 && self.sections_x < possible_sections_x as i32 {
|
||||
self.sections_x as u32
|
||||
} else {
|
||||
possible_sections_x
|
||||
};
|
||||
self.shown_sections_y =
|
||||
if self.sections_y > 0 && self.sections_y < possible_sections_y as i32 {
|
||||
self.sections_y as u32
|
||||
} else {
|
||||
possible_sections_y
|
||||
};
|
||||
|
||||
let width = if self.sections_x > 0 && self.sections_x < possible_sections_x as i32 {
|
||||
self.shown_sections_x = self.sections_x as u32;
|
||||
cal_width * self.sections_x as u32 + cal_pad * (self.sections_x as u32 - 1)
|
||||
} else {
|
||||
self.shown_sections_x = possible_sections_x;
|
||||
(geometry.width / (cal_width + cal_pad)) * (cal_width + cal_pad)
|
||||
};
|
||||
let height = if self.sections_y > 0 && self.sections_y < possible_sections_y as i32 {
|
||||
self.shown_sections_y = self.sections_y as u32;
|
||||
cal_height * self.sections_y as u32
|
||||
} else {
|
||||
self.shown_sections_y = possible_sections_y;
|
||||
(geometry.height / cal_height) * cal_height
|
||||
};
|
||||
self.geometry = Geometry {
|
||||
x: geometry.x,
|
||||
y: geometry.y,
|
||||
width: width,
|
||||
height: height,
|
||||
width: cal_width * self.shown_sections_x as u32
|
||||
+ cal_pad * (self.shown_sections_x as u32 - 1),
|
||||
height: cal_height * self.shown_sections_y as u32,
|
||||
};
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
|
||||
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
|
||||
let date_width = cal_font.auto_widest("0123456789").unwrap() * 2;
|
||||
|
||||
let cal_width = 8 * date_width + 7 * (date_width / 2);
|
||||
let cal_height =
|
||||
(self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
|
||||
let cal_pad = date_width * 2;
|
||||
|
||||
let sections_x = match self.sections_x {
|
||||
-1 => 1,
|
||||
0 => {
|
||||
return Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
}
|
||||
x => x,
|
||||
};
|
||||
let sections_y = match self.sections_y {
|
||||
-1 => 1,
|
||||
0 => {
|
||||
return Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
}
|
||||
y => y,
|
||||
};
|
||||
let width = cal_width * sections_x as u32 + cal_pad * (sections_x as u32 - 1);
|
||||
let height = cal_height * sections_y as u32;
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -3,8 +3,8 @@ use std::default::Default;
|
||||
use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
event::Event,
|
||||
fonts::FontMap,
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
|
||||
@@ -81,4 +81,16 @@ impl<'a> Widget for Clock {
|
||||
};
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
let digit_width = font.auto_widest("0123456789").unwrap();
|
||||
let colon_width = font.auto_widest(":").unwrap();
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: digit_width * 4 + colon_width,
|
||||
height: self.size.ceil() as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -3,8 +3,8 @@ use std::default::Default;
|
||||
use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
event::Event,
|
||||
fonts::FontMap,
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
|
||||
@@ -78,4 +78,15 @@ impl<'a> Widget for Date {
|
||||
};
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
|
||||
let width = (3. + 2. + 2. + 2. + 4.) * self.size / 2.;
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: width.ceil() as u32,
|
||||
height: font.height().ceil() as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-24
@@ -1,10 +1,10 @@
|
||||
use std::{
|
||||
cmp::{max, min, Ordering},
|
||||
collections::HashMap,
|
||||
env,
|
||||
io::Write,
|
||||
fs::{read_to_string, File},
|
||||
default::Default,
|
||||
env,
|
||||
fs::{read_to_string, File},
|
||||
io::Write,
|
||||
process::{exit, Command},
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
@@ -13,9 +13,9 @@ use std::{
|
||||
use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
event::{Event, Events, PointerButton, PointerEvent},
|
||||
fonts::FontMap,
|
||||
keyboard::{keysyms, KeyEvent},
|
||||
event::{Event, Events, PointerEvent, PointerButton},
|
||||
utils::desktop::{load_desktop_files, Desktop},
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
@@ -312,8 +312,7 @@ impl InterfaceWidget for Launcher {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
font.auto_draw_text(&mut prompt_line, fg, ">")
|
||||
.unwrap();
|
||||
font.auto_draw_text(&mut prompt_line, fg, ">").unwrap();
|
||||
|
||||
// Draw entries
|
||||
let dimfg = Color::GREY50;
|
||||
@@ -348,8 +347,7 @@ impl InterfaceWidget for Launcher {
|
||||
} else {
|
||||
x_max = max(
|
||||
x_max,
|
||||
font.auto_draw_text(&mut line, dimfg, &m.name)
|
||||
.unwrap(),
|
||||
font.auto_draw_text(&mut line, dimfg, &m.name).unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -452,10 +450,7 @@ impl Calc {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Calc{
|
||||
old,
|
||||
result: None,
|
||||
}
|
||||
Calc { old, result: None }
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
@@ -521,18 +516,18 @@ impl InterfaceWidget for Calc {
|
||||
|
||||
// Draw prompt
|
||||
let font = fonts.get_font(intf.font, intf.size);
|
||||
font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
fg,
|
||||
&format!(" {} ", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
font.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
fg,
|
||||
&format!(" {} ", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
font.auto_draw_text(&mut prompt_line, Color::BUFF, "=")
|
||||
.unwrap();
|
||||
|
||||
prompt_offset -= 16;
|
||||
prompt_offset -= line_height;
|
||||
if let Some(res) = &self.result {
|
||||
let c = if intf.selection == 0 {
|
||||
@@ -555,7 +550,8 @@ impl InterfaceWidget for Calc {
|
||||
};
|
||||
prompt_offset -= line_height;
|
||||
let mut result_line = view.offset((0, prompt_offset));
|
||||
font.auto_draw_text(&mut result_line, c, &format!("{} = {}", input, res)).unwrap();
|
||||
font.auto_draw_text(&mut result_line, c, &format!("{} = {}", input, res))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let content_height = min(
|
||||
@@ -588,9 +584,15 @@ pub struct Interface {
|
||||
}
|
||||
|
||||
impl Interface {
|
||||
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> Interface {
|
||||
pub fn new(
|
||||
events: Arc<Mutex<Events>>,
|
||||
fm: &mut FontMap,
|
||||
font: &'static str,
|
||||
size: f32,
|
||||
) -> Interface {
|
||||
fm.queue_font(
|
||||
font, size,
|
||||
font,
|
||||
size,
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 >=!,.-/()",
|
||||
);
|
||||
|
||||
@@ -708,6 +710,15 @@ impl Widget for Interface {
|
||||
self.inner.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 256,
|
||||
height: (self.inner.size.ceil() as u32) * 4 + 16,
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&mut self, event: &Event) {
|
||||
match event {
|
||||
Event::KeyEvent(e) => self.keyboard_input(e),
|
||||
@@ -715,7 +726,7 @@ impl Widget for Interface {
|
||||
Event::LauncherUpdate => {
|
||||
self.inner.dirty = true;
|
||||
self.launcher.update(&self.inner);
|
||||
},
|
||||
}
|
||||
Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
+66
-5
@@ -1,10 +1,6 @@
|
||||
use std::cmp::max;
|
||||
|
||||
use crate::{
|
||||
fonts::FontMap,
|
||||
state::State,
|
||||
widgets::{Geometry},
|
||||
};
|
||||
use crate::{fonts::FontMap, state::State, widgets::Geometry};
|
||||
|
||||
pub trait Layout {
|
||||
fn geometry_update(
|
||||
@@ -13,6 +9,8 @@ pub trait Layout {
|
||||
geometry: &Geometry,
|
||||
state: &mut State,
|
||||
) -> Geometry;
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry;
|
||||
}
|
||||
|
||||
pub struct HorizontalLayout {
|
||||
@@ -46,6 +44,22 @@ impl Layout for HorizontalLayout {
|
||||
geo.height = max_height;
|
||||
geo
|
||||
}
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
for w in self.widgets.iter() {
|
||||
let result = w.minimum_size(fonts, state);
|
||||
max_width += result.x + result.width;
|
||||
max_height = max(result.y + result.height, max_height);
|
||||
}
|
||||
Geometry {
|
||||
width: max_width,
|
||||
height: max_height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VerticalLayout {
|
||||
@@ -79,11 +93,28 @@ impl Layout for VerticalLayout {
|
||||
geo.height = max_height;
|
||||
geo
|
||||
}
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
for w in self.widgets.iter() {
|
||||
let result = w.minimum_size(fonts, state);
|
||||
max_width = max(result.x + result.width, max_width);
|
||||
max_height += result.y + result.height;
|
||||
}
|
||||
Geometry {
|
||||
width: max_width,
|
||||
height: max_height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WidgetUpdater {
|
||||
fn geometry_update(&mut self, idx: usize, fonts: &mut FontMap, geometry: &Geometry)
|
||||
-> Geometry;
|
||||
fn minimum_size(&mut self, idx: usize, fonts: &mut FontMap) -> Geometry;
|
||||
}
|
||||
|
||||
pub struct IndexedLayout {
|
||||
@@ -105,6 +136,10 @@ impl Layout for IndexedLayout {
|
||||
) -> Geometry {
|
||||
state.geometry_update(self.widget_idx, fonts, geometry)
|
||||
}
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
|
||||
state.minimum_size(self.widget_idx, fonts)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Margin {
|
||||
@@ -139,6 +174,16 @@ impl Layout for Margin {
|
||||
height: out.height + self.margin.1 + self.margin.3,
|
||||
}
|
||||
}
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
|
||||
let size = self.widget.minimum_size(fonts, state);
|
||||
Geometry {
|
||||
width: size.x + size.width + self.margin.0 + self.margin.2,
|
||||
height: size.y + size.height + self.margin.1 + self.margin.3,
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InvertedHorizontalLayout {
|
||||
@@ -171,4 +216,20 @@ impl Layout for InvertedHorizontalLayout {
|
||||
geo.height = max_height;
|
||||
geo
|
||||
}
|
||||
|
||||
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
for w in self.widgets.iter() {
|
||||
let result = w.minimum_size(fonts, state);
|
||||
max_width += result.x + result.width;
|
||||
max_height = max(result.y + result.height, max_height);
|
||||
}
|
||||
Geometry {
|
||||
width: max_width,
|
||||
height: max_height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -14,7 +14,7 @@ pub struct Line {
|
||||
|
||||
impl Line {
|
||||
pub fn new(thickness: u32) -> Line {
|
||||
Line{
|
||||
Line {
|
||||
geometry: Default::default(),
|
||||
thickness,
|
||||
}
|
||||
@@ -25,10 +25,12 @@ impl Widget for Line {
|
||||
fn geometry(&self) -> Geometry {
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn draw(&mut self, _fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||
view.memset(Color::WHITE);
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||
self.geometry = Geometry {
|
||||
x: geometry.x,
|
||||
@@ -38,4 +40,13 @@ impl Widget for Line {
|
||||
};
|
||||
self.geometry
|
||||
}
|
||||
|
||||
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
|
||||
Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: self.thickness,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,5 +1,4 @@
|
||||
//mod alsaaudio;
|
||||
mod pulseaudio;
|
||||
mod backlight;
|
||||
mod bar_widget;
|
||||
mod battery;
|
||||
@@ -7,18 +6,22 @@ mod calendar;
|
||||
mod clock;
|
||||
mod date;
|
||||
mod launcher;
|
||||
mod line;
|
||||
mod widget;
|
||||
mod layout;
|
||||
mod line;
|
||||
mod pulseaudio;
|
||||
mod widget;
|
||||
|
||||
//pub use alsaaudio::AlsaAudio;
|
||||
pub use pulseaudio::PulseAudio;
|
||||
pub use backlight::Backlight;
|
||||
pub use battery::Battery;
|
||||
pub use calendar::Calendar;
|
||||
pub use clock::Clock;
|
||||
pub use date::Date;
|
||||
pub use launcher::Interface;
|
||||
pub use layout::{
|
||||
HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin, VerticalLayout,
|
||||
WidgetUpdater,
|
||||
};
|
||||
pub use line::Line;
|
||||
pub use layout::{VerticalLayout, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin, WidgetUpdater};
|
||||
pub use pulseaudio::PulseAudio;
|
||||
pub use widget::{Geometry, Widget};
|
||||
|
||||
+90
-87
@@ -1,16 +1,13 @@
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
error::Error,
|
||||
os::fd::RawFd,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
error::Error,
|
||||
rc::Rc,
|
||||
cell::RefCell,
|
||||
os::fd::RawFd,
|
||||
};
|
||||
|
||||
use nix::unistd::{
|
||||
pipe, write, read,
|
||||
};
|
||||
use nix::unistd::{pipe, read, write};
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
@@ -21,22 +18,19 @@ use crate::{
|
||||
|
||||
use libpulse_binding::volume::ChannelVolumes;
|
||||
|
||||
fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) -> Result<(), Box<dyn Error>> {
|
||||
fn monitor(
|
||||
events: Arc<Mutex<Events>>,
|
||||
inner: Arc<Mutex<InnerAudio>>,
|
||||
pipe: RawFd,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
use libpulse_binding::{
|
||||
mainloop::{
|
||||
self,
|
||||
standard::{
|
||||
IterateResult,
|
||||
},
|
||||
api::Mainloop,
|
||||
events::io::FlagSet as IoFlagSet,
|
||||
},
|
||||
callbacks::ListResult,
|
||||
context::{
|
||||
Context,
|
||||
FlagSet,
|
||||
subscribe::{InterestMaskSet, Facility},
|
||||
State,
|
||||
subscribe::{Facility, InterestMaskSet},
|
||||
Context, FlagSet, State,
|
||||
},
|
||||
mainloop::{
|
||||
self, api::Mainloop, events::io::FlagSet as IoFlagSet, standard::IterateResult,
|
||||
},
|
||||
proplist::{properties, Proplist},
|
||||
volume::Volume,
|
||||
@@ -48,7 +42,9 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
|
||||
.unwrap();
|
||||
|
||||
let mut mainloop = mainloop::standard::Mainloop::new().unwrap();
|
||||
let context = Rc::new(RefCell::new(Context::new_with_proplist(&mainloop, "wldash_context", &proplist).unwrap()));
|
||||
let context = Rc::new(RefCell::new(
|
||||
Context::new_with_proplist(&mainloop, "wldash_context", &proplist).unwrap(),
|
||||
));
|
||||
context.borrow_mut().connect(None, FlagSet::NOFLAGS, None)?;
|
||||
|
||||
loop {
|
||||
@@ -63,33 +59,31 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
|
||||
let local_context = context.clone();
|
||||
let local_inner = inner.clone();
|
||||
let local_events = events.clone();
|
||||
context
|
||||
.borrow_mut()
|
||||
.set_subscribe_callback(Some(Box::new(move |facility, _operation, index| {
|
||||
match facility {
|
||||
Some(Facility::Sink) => {
|
||||
let introspector = local_context.borrow_mut().introspect();
|
||||
let inner = local_inner.clone();
|
||||
let events = local_events.clone();
|
||||
introspector.get_sink_info_by_index(index, move |res| {
|
||||
match res {
|
||||
ListResult::End | ListResult::Error => (),
|
||||
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name {
|
||||
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.volume = avg;
|
||||
inner.mute = sink_info.mute;
|
||||
inner.dirty = true;
|
||||
drop(inner);
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::AudioUpdate);
|
||||
},
|
||||
context.borrow_mut().set_subscribe_callback(Some(Box::new(
|
||||
move |facility, _operation, index| match facility {
|
||||
Some(Facility::Sink) => {
|
||||
let introspector = local_context.borrow_mut().introspect();
|
||||
let inner = local_inner.clone();
|
||||
let events = local_events.clone();
|
||||
introspector.get_sink_info_by_index(index, move |res| match res {
|
||||
ListResult::End | ListResult::Error => (),
|
||||
ListResult::Item(sink_info) => {
|
||||
if let Some(_) = &sink_info.name {
|
||||
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.volume = avg;
|
||||
inner.mute = sink_info.mute;
|
||||
inner.dirty = true;
|
||||
drop(inner);
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::AudioUpdate);
|
||||
}
|
||||
});
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
})));
|
||||
_ => (),
|
||||
},
|
||||
)));
|
||||
|
||||
context
|
||||
.borrow_mut()
|
||||
@@ -97,10 +91,10 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
|
||||
|
||||
let introspector = context.borrow_mut().introspect();
|
||||
let local_inner = inner.clone();
|
||||
introspector.get_sink_info_by_name("@DEFAULT_SINK@", move |res| {
|
||||
match res {
|
||||
ListResult::End | ListResult::Error => (),
|
||||
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name {
|
||||
introspector.get_sink_info_by_name("@DEFAULT_SINK@", move |res| match res {
|
||||
ListResult::End | ListResult::Error => (),
|
||||
ListResult::Item(sink_info) => {
|
||||
if let Some(_) = &sink_info.name {
|
||||
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
|
||||
let mut inner = local_inner.lock().unwrap();
|
||||
inner.volume = avg;
|
||||
@@ -110,46 +104,50 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
|
||||
drop(inner);
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::AudioUpdate);
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
drop(introspector);
|
||||
|
||||
let local_context = context.clone();
|
||||
let local_inner = inner.clone();
|
||||
let event_source = mainloop.new_io_event(pipe as i32, IoFlagSet::INPUT, Box::new(move |_, _, _| {
|
||||
let mut buf = [0; 8];
|
||||
_ = read(pipe, &mut buf);
|
||||
let event_source = mainloop.new_io_event(
|
||||
pipe as i32,
|
||||
IoFlagSet::INPUT,
|
||||
Box::new(move |_, _, _| {
|
||||
let mut buf = [0; 8];
|
||||
_ = read(pipe, &mut buf);
|
||||
|
||||
let mut inner = local_inner.lock().unwrap();
|
||||
let mut introspector = local_context.borrow_mut().introspect();
|
||||
match inner.last_click.take() {
|
||||
Some(Change::Volume(volume)) => {
|
||||
// do something
|
||||
let mut vol = inner.channel_volume.unwrap();
|
||||
vol.scale(Volume((volume * Volume::NORMAL.0 as f32).round() as u32));
|
||||
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||
},
|
||||
Some(Change::VolumeInc(value)) => {
|
||||
let mut vol = inner.channel_volume.unwrap();
|
||||
// apply step to volumes
|
||||
let step = (value * Volume::NORMAL.0 as f32).round() as i32;
|
||||
if step > 0 {
|
||||
vol.inc_clamp(Volume(step as u32), Volume::NORMAL);
|
||||
} else {
|
||||
vol.decrease(Volume(-step as u32));
|
||||
let mut inner = local_inner.lock().unwrap();
|
||||
let mut introspector = local_context.borrow_mut().introspect();
|
||||
match inner.last_click.take() {
|
||||
Some(Change::Volume(volume)) => {
|
||||
// do something
|
||||
let mut vol = inner.channel_volume.unwrap();
|
||||
vol.scale(Volume((volume * Volume::NORMAL.0 as f32).round() as u32));
|
||||
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||
}
|
||||
// HACK: It would be better to only update the volume from feedback, but axis
|
||||
// events fire fast and require the last set volume immediately for reference.
|
||||
inner.channel_volume = Some(vol);
|
||||
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||
},
|
||||
Some(Change::ToggleMute) => {
|
||||
introspector.set_sink_mute_by_name("@DEFAULT_SINK@", !inner.mute, None);
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
}));
|
||||
Some(Change::VolumeInc(value)) => {
|
||||
let mut vol = inner.channel_volume.unwrap();
|
||||
// apply step to volumes
|
||||
let step = (value * Volume::NORMAL.0 as f32).round() as i32;
|
||||
if step > 0 {
|
||||
vol.inc_clamp(Volume(step as u32), Volume::NORMAL);
|
||||
} else {
|
||||
vol.decrease(Volume(-step as u32));
|
||||
}
|
||||
// HACK: It would be better to only update the volume from feedback, but axis
|
||||
// events fire fast and require the last set volume immediately for reference.
|
||||
inner.channel_volume = Some(vol);
|
||||
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||
}
|
||||
Some(Change::ToggleMute) => {
|
||||
introspector.set_sink_mute_by_name("@DEFAULT_SINK@", !inner.mute, None);
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
loop {
|
||||
match mainloop.iterate(true) {
|
||||
@@ -167,7 +165,7 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
|
||||
fn start_monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) {
|
||||
thread::Builder::new()
|
||||
.name("audiomon".to_string())
|
||||
.spawn(move || { monitor(events, inner, pipe).unwrap() })
|
||||
.spawn(move || monitor(events, inner, pipe).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -191,10 +189,15 @@ pub struct PulseAudio {
|
||||
}
|
||||
|
||||
impl PulseAudio {
|
||||
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||
pub fn new(
|
||||
events: Arc<Mutex<Events>>,
|
||||
fm: &mut FontMap,
|
||||
font: &'static str,
|
||||
size: f32,
|
||||
) -> BarWidget {
|
||||
let (a, b) = pipe().unwrap();
|
||||
let audio = PulseAudio {
|
||||
inner: Arc::new(Mutex::new(InnerAudio{
|
||||
inner: Arc::new(Mutex::new(InnerAudio {
|
||||
volume: 0.0,
|
||||
channel_volume: None,
|
||||
mute: false,
|
||||
@@ -229,7 +232,7 @@ impl BarWidgetImpl for PulseAudio {
|
||||
fn click(&mut self, pos: f32, btn: PointerButton) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.last_click = match btn {
|
||||
PointerButton::Left => Some(Change::Volume(pos)),
|
||||
PointerButton::Left => Some(Change::Volume(pos)),
|
||||
PointerButton::Right => Some(Change::ToggleMute),
|
||||
PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)),
|
||||
PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)),
|
||||
|
||||
@@ -3,11 +3,7 @@ use std::{
|
||||
fmt,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
buffer::BufferView,
|
||||
fonts::FontMap,
|
||||
event::Event,
|
||||
};
|
||||
use crate::{buffer::BufferView, event::Event, fonts::FontMap};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct Geometry {
|
||||
@@ -49,8 +45,10 @@ impl Geometry {
|
||||
}
|
||||
|
||||
pub fn contains(&self, position: (u32, u32)) -> bool {
|
||||
position.0 >= self.x && position.0 < self.x + self.width &&
|
||||
position.1 >= self.y && position.1 < self.y + self.height
|
||||
position.0 >= self.x
|
||||
&& position.0 < self.x + self.width
|
||||
&& position.1 >= self.y
|
||||
&& position.1 < self.y + self.height
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +58,9 @@ pub trait Widget {
|
||||
}
|
||||
fn geometry(&self) -> Geometry;
|
||||
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry;
|
||||
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
|
||||
Default::default()
|
||||
}
|
||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry;
|
||||
fn event(&mut self, _event: &Event) {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user