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