Add calendar, refactor more
This commit is contained in:
Generated
-28
@@ -105,12 +105,6 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "const-cstr"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@@ -243,15 +237,6 @@ dependencies = [
|
|||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fontconfig"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b0653582d9c82645f95bacd0dc87b49a3126f7a9633be8cafa9c6d17d525847"
|
|
||||||
dependencies = [
|
|
||||||
"yeslogic-fontconfig-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuzzy-matcher"
|
name = "fuzzy-matcher"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -1102,7 +1087,6 @@ dependencies = [
|
|||||||
"calloop",
|
"calloop",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dbus",
|
"dbus",
|
||||||
"fontconfig",
|
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"itertools",
|
"itertools",
|
||||||
"memmap",
|
"memmap",
|
||||||
@@ -1128,15 +1112,3 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yeslogic-fontconfig-sys"
|
|
||||||
version = "4.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec657fd32bbcbeaef5c7bc8e10b3db95b143fab8db0a50079773dbf936fd4f73"
|
|
||||||
dependencies = [
|
|
||||||
"const-cstr",
|
|
||||||
"dlib",
|
|
||||||
"once_cell",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|||||||
+5
-1
@@ -3,6 +3,10 @@ name = "wldash2"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = "fat"
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -11,7 +15,7 @@ wayland-protocols = { version = "0.30", features = ["client", "unstable", "stagi
|
|||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
nix = "0.26"
|
nix = "0.26"
|
||||||
memmap = "0.7"
|
memmap = "0.7"
|
||||||
fontconfig = "0.6.0"
|
#fontconfig = "0.6.0"
|
||||||
rusttype = "^0.9"
|
rusttype = "^0.9"
|
||||||
calloop = { version = "0.10" }
|
calloop = { version = "0.10" }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ pub struct BufferManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BufferManager {
|
impl BufferManager {
|
||||||
|
pub fn new() -> BufferManager {
|
||||||
|
BufferManager {
|
||||||
|
buffers: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear_buffers(&mut self) {
|
pub fn clear_buffers(&mut self) {
|
||||||
for buf in self.buffers.iter_mut() {
|
for buf in self.buffers.iter_mut() {
|
||||||
buf.buffer.destroy()
|
buf.buffer.destroy()
|
||||||
|
|||||||
+8
-8
@@ -1,24 +1,24 @@
|
|||||||
//! Utility module for fonts
|
//! Utility module for fonts
|
||||||
|
|
||||||
use crate::draw;
|
use crate::draw;
|
||||||
use fontconfig::Fontconfig as FontConfig;
|
//use fontconfig::Fontconfig as FontConfig;
|
||||||
use rusttype::Font;
|
use rusttype::Font;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
mem,
|
|
||||||
rc::Rc,
|
|
||||||
thread,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
hash,
|
hash,
|
||||||
io::Read,
|
io::Read,
|
||||||
|
mem,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
rc::Rc,
|
||||||
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// FontRef is used to store Fonts on widgets.
|
/// FontRef is used to store Fonts on widgets.
|
||||||
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
||||||
|
|
||||||
|
/*
|
||||||
/// FontSeeker is a marker struct that is used to look up fonts
|
/// FontSeeker is a marker struct that is used to look up fonts
|
||||||
pub(crate) struct FontSeeker;
|
pub(crate) struct FontSeeker;
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ impl FontSeeker {
|
|||||||
fc.find(name, None).unwrap().path
|
fc.find(name, None).unwrap().path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
/// FontLoader is a marker struct that is used to load files
|
/// FontLoader is a marker struct that is used to load files
|
||||||
pub(crate) struct FontLoader;
|
pub(crate) struct FontLoader;
|
||||||
|
|
||||||
@@ -113,7 +113,8 @@ impl FontMap {
|
|||||||
let path = if v.0.starts_with("/") {
|
let path = if v.0.starts_with("/") {
|
||||||
std::path::PathBuf::from(v.0)
|
std::path::PathBuf::from(v.0)
|
||||||
} else {
|
} else {
|
||||||
FontSeeker::from_string(v.0)
|
//FontSeeker::from_string(v.0)
|
||||||
|
panic!("required FontSeeker");
|
||||||
};
|
};
|
||||||
let fontref = Box::leak(Box::new(
|
let fontref = Box::leak(Box::new(
|
||||||
FontLoader::from_path(path).expect("unable to load font"),
|
FontLoader::from_path(path).expect("unable to load font"),
|
||||||
@@ -158,4 +159,3 @@ impl MaybeFontMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+92
-75
@@ -3,11 +3,11 @@ mod color;
|
|||||||
mod draw;
|
mod draw;
|
||||||
mod fonts;
|
mod fonts;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
|
mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
mod state;
|
|
||||||
|
|
||||||
use wayland_client::{Connection, QueueHandle, WaylandSource,};
|
use wayland_client::{Connection, QueueHandle, WaylandSource};
|
||||||
|
|
||||||
use calloop::{
|
use calloop::{
|
||||||
timer::{TimeoutAction, Timer},
|
timer::{TimeoutAction, Timer},
|
||||||
@@ -15,27 +15,16 @@ use calloop::{
|
|||||||
};
|
};
|
||||||
use chrono::{Duration, Local, Timelike};
|
use chrono::{Duration, Local, Timelike};
|
||||||
|
|
||||||
use buffer::{BufferManager, BufferView};
|
use buffer::BufferView;
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use fonts::{MaybeFontMap, FontMap};
|
use fonts::{FontMap, MaybeFontMap};
|
||||||
use keyboard::Keyboard;
|
use state::{Event, Events, State};
|
||||||
use widgets::{
|
use widgets::{
|
||||||
Backlight, Battery, Clock, Date, Geometry, Interface, Line, WidgetUpdater,
|
Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||||
|
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget,
|
||||||
};
|
};
|
||||||
use state::State;
|
|
||||||
|
|
||||||
use std::thread;
|
use std::{rc::Rc, thread};
|
||||||
|
|
||||||
impl WidgetUpdater for State {
|
|
||||||
fn geometry_update(
|
|
||||||
&mut self,
|
|
||||||
idx: usize,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
) -> Geometry {
|
|
||||||
self.widgets[idx].geometry_update(fonts, geometry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let font_thread = thread::spawn(move || {
|
let font_thread = thread::spawn(move || {
|
||||||
@@ -49,6 +38,21 @@ fn main() {
|
|||||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
||||||
32.,
|
32.,
|
||||||
);
|
);
|
||||||
|
fm.queue_font_path(
|
||||||
|
"monospace",
|
||||||
|
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
||||||
|
12.,
|
||||||
|
);
|
||||||
|
fm.queue_font_path(
|
||||||
|
"monospace",
|
||||||
|
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
||||||
|
12. * 1.5,
|
||||||
|
);
|
||||||
|
fm.queue_font_path(
|
||||||
|
"monospace",
|
||||||
|
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
||||||
|
12. * 2.0,
|
||||||
|
);
|
||||||
fm.load_fonts();
|
fm.load_fonts();
|
||||||
fm
|
fm
|
||||||
});
|
});
|
||||||
@@ -60,19 +64,34 @@ fn main() {
|
|||||||
let display = conn.display();
|
let display = conn.display();
|
||||||
display.get_registry(&qhandle, ());
|
display.get_registry(&qhandle, ());
|
||||||
|
|
||||||
let bufmgr = BufferManager {
|
|
||||||
buffers: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
||||||
|
|
||||||
|
let events = Events::new(ping_sender);
|
||||||
|
|
||||||
let clock = Box::new(Clock::new("sans", 128.));
|
let clock = Box::new(Clock::new("sans", 128.));
|
||||||
|
// let calendar = Box::new(Calendar::new("monospace", 12.0, 1, -1));
|
||||||
let date = Box::new(Date::new("sans", 48.));
|
let date = Box::new(Date::new("sans", 48.));
|
||||||
let line = Box::new(Line::new());
|
let line = Box::new(Line::new());
|
||||||
let launcher = Box::new(Interface::new("monospace", 32.));
|
let launcher = Box::new(Interface::new("monospace", 32.));
|
||||||
let battery = Box::new(Battery::new(ping_sender, "sans", 24.));
|
let battery = Box::new(Battery::new(events.clone(), "sans", 24.));
|
||||||
let backlight = Box::new(Backlight::new("intel_backlight", "sans", 24.));
|
let backlight = Box::new(Backlight::new("intel_backlight", "sans", 24.));
|
||||||
|
|
||||||
|
let widgets: Vec<Box<dyn Widget>> =
|
||||||
|
vec![clock, date, battery, backlight, line, launcher];
|
||||||
|
let layout = Rc::new(VerticalLayout::new(vec![
|
||||||
|
HorizontalLayout::new(vec![
|
||||||
|
IndexedLayout::new(0),
|
||||||
|
Margin::new(IndexedLayout::new(1), (16, 8, 0, 0)),
|
||||||
|
VerticalLayout::new(vec![
|
||||||
|
Margin::new(IndexedLayout::new(2), (16, 8, 8, 0)),
|
||||||
|
Margin::new(IndexedLayout::new(3), (16, 8, 8, 0)),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
IndexedLayout::new(4),
|
||||||
|
IndexedLayout::new(5),
|
||||||
|
// InvertedHorizontalLayout::new(vec![IndexedLayout::new(5), IndexedLayout::new(6)]),
|
||||||
|
]));
|
||||||
|
|
||||||
let mut event_loop: EventLoop<State> =
|
let mut event_loop: EventLoop<State> =
|
||||||
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
||||||
|
|
||||||
@@ -86,7 +105,12 @@ fn main() {
|
|||||||
|
|
||||||
handle
|
handle
|
||||||
.insert_source(ping_source, |(), &mut (), state| {
|
.insert_source(ping_source, |(), &mut (), state| {
|
||||||
state.widgets[2].set_dirty(true);
|
let events = state.events.lock().unwrap().flush();
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
for event in events.iter() {
|
||||||
|
widget.event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
})
|
})
|
||||||
.expect("Failed to insert ping source!");
|
.expect("Failed to insert ping source!");
|
||||||
@@ -101,8 +125,9 @@ fn main() {
|
|||||||
.with_nanosecond(0)
|
.with_nanosecond(0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let d = target - now;
|
let d = target - now;
|
||||||
state.widgets[0].set_dirty(true);
|
for widget in state.widgets.iter_mut() {
|
||||||
state.widgets[1].set_dirty(true);
|
widget.event(&Event::NewMinute);
|
||||||
|
}
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
|
|
||||||
// The timer event source requires us to return a TimeoutAction to
|
// The timer event source requires us to return a TimeoutAction to
|
||||||
@@ -111,22 +136,7 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.expect("Failed to insert event source!");
|
.expect("Failed to insert event source!");
|
||||||
|
|
||||||
let mut state = State {
|
let mut state = State::new(widgets, layout, MaybeFontMap::Waiting(font_thread), events);
|
||||||
running: true,
|
|
||||||
dirty: true,
|
|
||||||
activated: false,
|
|
||||||
base_surface: None,
|
|
||||||
wm_base: None,
|
|
||||||
xdg_surface: None,
|
|
||||||
wl_shm: None,
|
|
||||||
xdg_activation: None,
|
|
||||||
configured: false,
|
|
||||||
dimensions: (320, 240),
|
|
||||||
bufmgr: bufmgr,
|
|
||||||
widgets: vec![clock, date, battery, backlight, line, launcher],
|
|
||||||
keyboard: Keyboard::new(),
|
|
||||||
fonts: MaybeFontMap::Waiting(font_thread),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut damage = Vec::new();
|
let mut damage = Vec::new();
|
||||||
for _ in 0..state.widgets.len() {
|
for _ in 0..state.widgets.len() {
|
||||||
@@ -142,7 +152,6 @@ fn main() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut drew = false;
|
|
||||||
let mut force = false;
|
let mut force = false;
|
||||||
if state.bufmgr.buffers.len() == 0 {
|
if state.bufmgr.buffers.len() == 0 {
|
||||||
state.add_buffer(&qhandle);
|
state.add_buffer(&qhandle);
|
||||||
@@ -168,43 +177,51 @@ fn main() {
|
|||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
|
|
||||||
let surface = state.base_surface.as_ref().unwrap().clone();
|
let surface = state.base_surface.as_ref().unwrap().clone();
|
||||||
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
if force {
|
||||||
if force || widget.get_dirty() {
|
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
||||||
widget.set_dirty(false);
|
if force || widget.get_dirty() {
|
||||||
drew = true;
|
let geo = widget.geometry();
|
||||||
|
|
||||||
let geo = widget.geometry();
|
|
||||||
let old_damage = damage[idx];
|
|
||||||
|
|
||||||
if !force {
|
|
||||||
bufview.subgeometry(old_damage).unwrap().memset(&bg);
|
|
||||||
} else {
|
|
||||||
bufview.subgeometry(geo).unwrap().memset(&bg);
|
bufview.subgeometry(geo).unwrap().memset(&bg);
|
||||||
}
|
|
||||||
|
|
||||||
let mut subview = bufview.subgeometry(geo).unwrap();
|
let mut subview = bufview.subgeometry(geo).unwrap();
|
||||||
let new_damage = widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
damage[idx] = widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
||||||
let combined_damage = new_damage.expand(old_damage);
|
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
||||||
damage[idx] = new_damage;
|
}
|
||||||
surface.damage_buffer(
|
}
|
||||||
combined_damage.x as i32,
|
surface.damage_buffer(0, 0, 0x7FFFFFFF, 0x7FFFFFFF)
|
||||||
combined_damage.y as i32,
|
} else {
|
||||||
combined_damage.width as i32,
|
let mut drew = false;
|
||||||
combined_damage.height as i32,
|
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
||||||
);
|
if force || widget.get_dirty() {
|
||||||
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
drew = true;
|
||||||
|
|
||||||
|
let old_damage = damage[idx];
|
||||||
|
bufview.subgeometry(old_damage).unwrap().memset(&bg);
|
||||||
|
|
||||||
|
let geo = widget.geometry();
|
||||||
|
let mut subview = bufview.subgeometry(geo).unwrap();
|
||||||
|
|
||||||
|
let new_damage =
|
||||||
|
widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
||||||
|
let combined_damage = new_damage.expand(old_damage);
|
||||||
|
damage[idx] = new_damage;
|
||||||
|
|
||||||
|
surface.damage_buffer(
|
||||||
|
combined_damage.x as i32,
|
||||||
|
combined_damage.y as i32,
|
||||||
|
combined_damage.width as i32,
|
||||||
|
combined_damage.height as i32,
|
||||||
|
);
|
||||||
|
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !drew {
|
||||||
|
buf.release();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !drew {
|
|
||||||
buf.release();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if force {
|
|
||||||
surface.damage_buffer(0, 0, 0x7FFFFFFF, 0x7FFFFFFF)
|
|
||||||
}
|
|
||||||
surface.attach(Some(&buf.buffer), 0, 0);
|
surface.attach(Some(&buf.buffer), 0, 0);
|
||||||
surface.commit();
|
surface.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-41
@@ -1,8 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
process::exit,
|
process::exit,
|
||||||
|
rc::Rc,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use calloop::ping::Ping;
|
||||||
|
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||||
@@ -18,31 +22,93 @@ use wayland_protocols::xdg::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::BufferManager,
|
buffer::BufferManager,
|
||||||
fonts::MaybeFontMap,
|
fonts::{FontMap, MaybeFontMap},
|
||||||
keyboard::Keyboard,
|
keyboard::{KeyEvent, Keyboard},
|
||||||
widgets::{
|
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
||||||
Geometry, HorizontalLayout, IndexedLayout, Layout, Margin, VerticalLayout, Widget,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
NewMinute,
|
||||||
|
PowerUpdate,
|
||||||
|
KeyEvent(KeyEvent),
|
||||||
|
TokenUpdate(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Events {
|
||||||
|
dirty: bool,
|
||||||
|
events: Vec<Event>,
|
||||||
|
ping: Ping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Events {
|
||||||
|
pub fn new(ping: Ping) -> Arc<Mutex<Events>> {
|
||||||
|
Arc::new(Mutex::new(Events {
|
||||||
|
dirty: false,
|
||||||
|
events: Vec::new(),
|
||||||
|
ping,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_event(&mut self, ev: Event) {
|
||||||
|
self.events.push(ev);
|
||||||
|
if !self.dirty {
|
||||||
|
self.dirty = true;
|
||||||
|
self.ping.ping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(&mut self) -> Vec<Event> {
|
||||||
|
self.dirty = false;
|
||||||
|
self.events.drain(..).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub running: bool,
|
pub running: bool,
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
pub activated: bool,
|
activated: bool,
|
||||||
pub base_surface: Option<wl_surface::WlSurface>,
|
pub base_surface: Option<wl_surface::WlSurface>,
|
||||||
pub wm_base: Option<xdg_wm_base::XdgWmBase>,
|
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
||||||
pub xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
|
xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
|
||||||
pub wl_shm: Option<wl_shm::WlShm>,
|
wl_shm: Option<wl_shm::WlShm>,
|
||||||
pub xdg_activation: Option<xdg_activation_v1::XdgActivationV1>,
|
xdg_activation: Option<xdg_activation_v1::XdgActivationV1>,
|
||||||
pub configured: bool,
|
pub configured: bool,
|
||||||
pub dimensions: (i32, i32),
|
pub dimensions: (i32, i32),
|
||||||
pub bufmgr: BufferManager,
|
pub bufmgr: BufferManager,
|
||||||
pub widgets: Vec<Box<dyn Widget>>,
|
pub widgets: Vec<Box<dyn Widget>>,
|
||||||
pub keyboard: Keyboard,
|
keyboard: Keyboard,
|
||||||
pub fonts: MaybeFontMap,
|
pub fonts: MaybeFontMap,
|
||||||
|
pub events: Arc<Mutex<Events>>,
|
||||||
|
layout: Rc<Box<dyn Layout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
pub fn new(
|
||||||
|
widgets: Vec<Box<dyn Widget>>,
|
||||||
|
layout: Rc<Box<dyn Layout>>,
|
||||||
|
fonts: MaybeFontMap,
|
||||||
|
events: Arc<Mutex<Events>>,
|
||||||
|
) -> State {
|
||||||
|
State {
|
||||||
|
running: true,
|
||||||
|
dirty: true,
|
||||||
|
activated: false,
|
||||||
|
base_surface: None,
|
||||||
|
wm_base: None,
|
||||||
|
xdg_surface: None,
|
||||||
|
wl_shm: None,
|
||||||
|
xdg_activation: None,
|
||||||
|
configured: false,
|
||||||
|
dimensions: (320, 240),
|
||||||
|
bufmgr: BufferManager::new(),
|
||||||
|
keyboard: Keyboard::new(),
|
||||||
|
widgets,
|
||||||
|
fonts,
|
||||||
|
events,
|
||||||
|
layout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_buffer(&mut self, qh: &QueueHandle<Self>) {
|
pub fn add_buffer(&mut self, qh: &QueueHandle<Self>) {
|
||||||
self.bufmgr.add_buffer(
|
self.bufmgr.add_buffer(
|
||||||
self.wl_shm.as_ref().expect("missing wl_shm"),
|
self.wl_shm.as_ref().expect("missing wl_shm"),
|
||||||
@@ -68,6 +134,17 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WidgetUpdater for State {
|
||||||
|
fn geometry_update(
|
||||||
|
&mut self,
|
||||||
|
idx: usize,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
) -> Geometry {
|
||||||
|
self.widgets[idx].geometry_update(fonts, geometry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
@@ -264,36 +341,9 @@ impl Dispatch<xdg_toplevel::XdgToplevel, ()> for State {
|
|||||||
if state.dimensions != (width, height) {
|
if state.dimensions != (width, height) {
|
||||||
state.bufmgr.clear_buffers();
|
state.bufmgr.clear_buffers();
|
||||||
state.dimensions = (width, height);
|
state.dimensions = (width, height);
|
||||||
let mut layout = VerticalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(HorizontalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(IndexedLayout { widget_idx: 0 }),
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 1 }),
|
|
||||||
margin: (16, 8, 0, 0),
|
|
||||||
}),
|
|
||||||
Box::new(VerticalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 2 }),
|
|
||||||
margin: (16, 8, 8, 0),
|
|
||||||
}),
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 3 }),
|
|
||||||
margin: (16, 8, 8, 0),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Box::new(IndexedLayout { widget_idx: 4 }),
|
|
||||||
Box::new(IndexedLayout { widget_idx: 5 }),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
state.fonts.resolve();
|
state.fonts.resolve();
|
||||||
let fonts = state.fonts.unwrap();
|
let fonts = state.fonts.unwrap();
|
||||||
|
let layout = state.layout.clone();
|
||||||
layout.geometry_update(
|
layout.geometry_update(
|
||||||
&mut fonts.borrow_mut(),
|
&mut fonts.borrow_mut(),
|
||||||
&Geometry {
|
&Geometry {
|
||||||
@@ -355,8 +405,9 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let k = state.keyboard.key(serial, time, key, kbstate);
|
let k = state.keyboard.key(serial, time, key, kbstate);
|
||||||
|
let ev = Event::KeyEvent(k);
|
||||||
for widget in state.widgets.iter_mut() {
|
for widget in state.widgets.iter_mut() {
|
||||||
widget.keyboard_input(&k);
|
widget.event(&ev);
|
||||||
}
|
}
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
@@ -372,6 +423,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|||||||
.modifiers(mods_depressed, mods_latched, mods_locked, group);
|
.modifiers(mods_depressed, mods_latched, mods_locked, group);
|
||||||
}
|
}
|
||||||
wl_keyboard::Event::Keymap { format, fd, size } => {
|
wl_keyboard::Event::Keymap { format, fd, size } => {
|
||||||
|
// TODO: Keymap loading blocks xdg configure, consider delaying
|
||||||
state.keyboard.keymap(format, fd, size);
|
state.keyboard.keymap(format, fd, size);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -402,8 +454,9 @@ impl Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ()> for State {
|
|||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
xdg_activation_token_v1::Event::Done { token } => {
|
xdg_activation_token_v1::Event::Done { token } => {
|
||||||
|
let ev = Event::TokenUpdate(token);
|
||||||
for widget in state.widgets.iter_mut() {
|
for widget in state.widgets.iter_mut() {
|
||||||
widget.token_update(&token);
|
widget.event(&ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ pub struct Backlight {
|
|||||||
device_path: PathBuf,
|
device_path: PathBuf,
|
||||||
cur: u64,
|
cur: u64,
|
||||||
max: u64,
|
max: u64,
|
||||||
dirty: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backlight {
|
impl Backlight {
|
||||||
@@ -34,7 +33,6 @@ impl Backlight {
|
|||||||
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
||||||
cur: 0,
|
cur: 0,
|
||||||
max: 0,
|
max: 0,
|
||||||
dirty: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dev.update();
|
dev.update();
|
||||||
@@ -43,12 +41,6 @@ impl Backlight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BarWidgetImpl for Backlight {
|
impl BarWidgetImpl for Backlight {
|
||||||
fn get_dirty(&self) -> bool {
|
|
||||||
self.dirty
|
|
||||||
}
|
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.dirty = dirty
|
|
||||||
}
|
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"backlight"
|
"backlight"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub trait BarWidgetImpl {
|
pub trait BarWidgetImpl {
|
||||||
fn get_dirty(&self) -> bool;
|
fn get_dirty(&self) -> bool {
|
||||||
fn set_dirty(&mut self, dirty: bool);
|
false
|
||||||
|
}
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn value(&self) -> f32;
|
fn value(&self) -> f32;
|
||||||
fn color(&self) -> Color;
|
fn color(&self) -> Color;
|
||||||
@@ -27,7 +28,9 @@ impl BarWidget {
|
|||||||
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, font: &'static str, size: f32) -> BarWidget {
|
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, font: &'static str, size: f32) -> BarWidget {
|
||||||
BarWidget {
|
BarWidget {
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
inner_widget, font, size,
|
inner_widget,
|
||||||
|
font,
|
||||||
|
size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,10 +44,6 @@ impl Widget for BarWidget {
|
|||||||
self.inner_widget.get_dirty()
|
self.inner_widget.get_dirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.inner_widget.set_dirty(dirty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let font = fonts.get_font(self.font, self.size);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
|
|||||||
+15
-14
@@ -4,8 +4,6 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use calloop::ping::Ping;
|
|
||||||
|
|
||||||
use dbus::blocking::{
|
use dbus::blocking::{
|
||||||
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
|
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
|
||||||
LocalConnection,
|
LocalConnection,
|
||||||
@@ -13,6 +11,7 @@ use dbus::blocking::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::Color,
|
color::Color,
|
||||||
|
state::{Event, Events},
|
||||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,9 +27,10 @@ enum UpowerBatteryState {
|
|||||||
struct InnerBattery {
|
struct InnerBattery {
|
||||||
value: f32,
|
value: f32,
|
||||||
state: UpowerBatteryState,
|
state: UpowerBatteryState,
|
||||||
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, ping: Ping) {
|
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("battmon".to_string())
|
.name("battmon".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
@@ -84,11 +84,15 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, ping: Ping) {
|
|||||||
6 => UpowerBatteryState::Discharging,
|
6 => UpowerBatteryState::Discharging,
|
||||||
_ => UpowerBatteryState::Unknown,
|
_ => UpowerBatteryState::Unknown,
|
||||||
};
|
};
|
||||||
ping.ping();
|
inner.dirty = true;
|
||||||
|
let mut events = events.lock().unwrap();
|
||||||
|
events.add_event(Event::PowerUpdate);
|
||||||
}
|
}
|
||||||
"Percentage" => {
|
"Percentage" => {
|
||||||
inner.value = value.0.as_f64().unwrap() as f32 / 100.;
|
inner.value = value.0.as_f64().unwrap() as f32 / 100.;
|
||||||
ping.ping();
|
inner.dirty = true;
|
||||||
|
let mut events = events.lock().unwrap();
|
||||||
|
events.add_event(Event::PowerUpdate);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -107,35 +111,32 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, ping: Ping) {
|
|||||||
|
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
inner: Arc<Mutex<InnerBattery>>,
|
inner: Arc<Mutex<InnerBattery>>,
|
||||||
dirty: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
pub fn new(ping: Ping, font: &'static str, size: f32) -> BarWidget {
|
pub fn new(events: Arc<Mutex<Events>>, 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.,
|
||||||
state: UpowerBatteryState::Unknown,
|
state: UpowerBatteryState::Unknown,
|
||||||
|
dirty: false,
|
||||||
})),
|
})),
|
||||||
dirty: false,
|
|
||||||
};
|
};
|
||||||
start_monitor(battery.inner.clone(), ping);
|
start_monitor(battery.inner.clone(), events);
|
||||||
BarWidget::new(Box::new(battery), font, size)
|
BarWidget::new(Box::new(battery), font, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BarWidgetImpl for Battery {
|
impl BarWidgetImpl for Battery {
|
||||||
fn get_dirty(&self) -> bool {
|
fn get_dirty(&self) -> bool {
|
||||||
self.dirty
|
self.inner.lock().unwrap().dirty
|
||||||
}
|
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.dirty = dirty
|
|
||||||
}
|
}
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"battery"
|
"battery"
|
||||||
}
|
}
|
||||||
fn value(&self) -> f32 {
|
fn value(&self) -> f32 {
|
||||||
let inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
inner.dirty = false;
|
||||||
inner.value
|
inner.value
|
||||||
}
|
}
|
||||||
fn color(&self) -> Color {
|
fn color(&self) -> Color {
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
buffer::BufferView,
|
||||||
|
color::Color,
|
||||||
|
fonts::FontMap,
|
||||||
|
state::Event,
|
||||||
|
widgets::{Geometry, Widget},
|
||||||
|
};
|
||||||
|
|
||||||
|
use chrono::{Datelike, Local, NaiveDate};
|
||||||
|
|
||||||
|
pub struct Calendar {
|
||||||
|
font: &'static str,
|
||||||
|
sections_x: i32,
|
||||||
|
sections_y: i32,
|
||||||
|
size: f32,
|
||||||
|
dirty: bool,
|
||||||
|
geometry: Geometry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Calendar {
|
||||||
|
pub fn new(font: &'static str, size: f32, sections_x: i32, sections_y: i32) -> Calendar {
|
||||||
|
Calendar {
|
||||||
|
font,
|
||||||
|
size,
|
||||||
|
sections_x,
|
||||||
|
sections_y,
|
||||||
|
dirty: true,
|
||||||
|
geometry: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_month(
|
||||||
|
&mut self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
mut view: &mut BufferView,
|
||||||
|
orig: NaiveDate,
|
||||||
|
mut time: NaiveDate,
|
||||||
|
) {
|
||||||
|
let black = Color::new(0., 0., 0., 1.);
|
||||||
|
let white = Color::new(1., 1., 1., 1.);
|
||||||
|
let dim = Color::new(0.8, 0.8, 0.8, 1.);
|
||||||
|
let dimmer = Color::new(0.75, 0.75, 0.75, 1.);
|
||||||
|
let month_str = match time.month() {
|
||||||
|
1 => "January",
|
||||||
|
2 => "February",
|
||||||
|
3 => "March",
|
||||||
|
4 => "April",
|
||||||
|
5 => "May",
|
||||||
|
6 => "June",
|
||||||
|
7 => "July",
|
||||||
|
8 => "August",
|
||||||
|
9 => "September",
|
||||||
|
10 => "October",
|
||||||
|
11 => "November",
|
||||||
|
12 => "December",
|
||||||
|
_ => panic!("impossible value"),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut y_off = 1;
|
||||||
|
// TODO: Fix offsets:
|
||||||
|
// - Headline font is not correctly accounted for
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the week day
|
||||||
|
//
|
||||||
|
for idx in 1..8 {
|
||||||
|
let day_font = fonts.get_font(self.font, self.size);
|
||||||
|
let wk_chr = match idx {
|
||||||
|
1 => "MON",
|
||||||
|
2 => "TUE",
|
||||||
|
3 => "WED",
|
||||||
|
4 => "THU",
|
||||||
|
5 => "FRI",
|
||||||
|
6 => "SAT",
|
||||||
|
7 => "SUN",
|
||||||
|
_ => panic!("impossible value"),
|
||||||
|
};
|
||||||
|
|
||||||
|
day_font
|
||||||
|
.auto_draw_text(
|
||||||
|
&mut view
|
||||||
|
.offset((
|
||||||
|
idx * (self.size * 2.5).ceil() as u32 + (self.size / 5.).ceil() as u32,
|
||||||
|
y_off * (self.size * 1.8).ceil() as u32
|
||||||
|
+ (self.size * 1.).ceil() as u32,
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
|
&black,
|
||||||
|
&white,
|
||||||
|
&wk_chr,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the month
|
||||||
|
//
|
||||||
|
if time.year() != orig.year() {
|
||||||
|
let year_font = fonts.get_font(self.font, self.size * 1.5);
|
||||||
|
year_font
|
||||||
|
.auto_draw_text(
|
||||||
|
&mut view.offset(((self.size * 17.).ceil() as u32, 0)).unwrap(),
|
||||||
|
&black,
|
||||||
|
&dim,
|
||||||
|
&format!("{:}", time.year()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cal_font = fonts.get_font(self.font, self.size * 2.);
|
||||||
|
cal_font
|
||||||
|
.auto_draw_text(&mut view, &black, &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 week number
|
||||||
|
//
|
||||||
|
let wk = time.iso_week();
|
||||||
|
cal_font
|
||||||
|
.auto_draw_text(
|
||||||
|
&mut view
|
||||||
|
.offset((
|
||||||
|
0,
|
||||||
|
y_off * (self.size * 1.8).ceil() as u32
|
||||||
|
+ (self.size * 2.).ceil() as u32,
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
|
&black,
|
||||||
|
&dimmer,
|
||||||
|
&format!("{:02}", wk.week()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
x_pos += 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the dates
|
||||||
|
//
|
||||||
|
while x_pos < 8 {
|
||||||
|
let c = if time.day() == orig.day() && time.month() == orig.month() {
|
||||||
|
Color::new(1.0, 1.0, 1.0, 1.0)
|
||||||
|
} else {
|
||||||
|
Color::new(0.5, 0.5, 0.5, 1.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
cal_font
|
||||||
|
.auto_draw_text(
|
||||||
|
&mut view
|
||||||
|
.offset((
|
||||||
|
x_pos * (self.size * 2.5).ceil() as u32,
|
||||||
|
y_off * (self.size * 1.8).ceil() as u32 + (self.size * 2.) as u32,
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
|
&black,
|
||||||
|
&c,
|
||||||
|
&format!("{:02}", time.day()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let t = time.with_day(time.day() + 1);
|
||||||
|
if t.is_none() {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
time = t.unwrap();
|
||||||
|
x_pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
y_off += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for Calendar {
|
||||||
|
fn get_dirty(&self) -> bool {
|
||||||
|
self.dirty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self) -> Geometry {
|
||||||
|
self.geometry
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
Event::NewMinute => {
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
|
let time = Local::now().naive_local().date();
|
||||||
|
|
||||||
|
let cal_height = (self.size * 16.25).ceil() as u32;
|
||||||
|
let cal_width = (7. * self.size * 3. + self.size * 2.).ceil() as u32;
|
||||||
|
let cal_pad = (3. * self.size).ceil() as u32;
|
||||||
|
let sections_y = if self.sections_y > 0 {
|
||||||
|
self.sections_y as u32
|
||||||
|
} else {
|
||||||
|
self.geometry.height / cal_height
|
||||||
|
};
|
||||||
|
let sections_x = if self.sections_x > 0 {
|
||||||
|
self.sections_x as u32
|
||||||
|
} else {
|
||||||
|
self.geometry.width / (cal_height + cal_pad)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut t = time.with_day(1).unwrap();
|
||||||
|
let cals = sections_y * sections_x - 1;
|
||||||
|
if cals >=3 {
|
||||||
|
t = t.pred_opt().unwrap().with_day(1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ydx in 0..sections_y {
|
||||||
|
for idx in 0..sections_x {
|
||||||
|
self.draw_month(
|
||||||
|
fonts,
|
||||||
|
&mut view
|
||||||
|
.offset(((cal_width + cal_pad) * idx, (cal_height) * ydx))
|
||||||
|
.unwrap(),
|
||||||
|
time,
|
||||||
|
t,
|
||||||
|
);
|
||||||
|
t = if t.month() == 12 {
|
||||||
|
t.with_year(t.year() + 1).unwrap().with_month(1).unwrap()
|
||||||
|
} else {
|
||||||
|
t.with_month(t.month() + 1).unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.dirty = false;
|
||||||
|
self.geometry
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
|
let cal_width = (7. * self.size * 3. + self.size * 2.).ceil() as u32;
|
||||||
|
let cal_height = (self.size * 16.25).ceil() as u32; // TODO: Calculate from font sizes
|
||||||
|
let cal_pad = (self.size * 3.).ceil() as u32;
|
||||||
|
let width = if self.sections_x > 0 {
|
||||||
|
cal_width * self.sections_x as u32 + cal_pad * (self.sections_x as u32 - 1)
|
||||||
|
} else {
|
||||||
|
(geometry.width / (cal_width + cal_pad)) * (cal_width + cal_pad)
|
||||||
|
};
|
||||||
|
let height = if self.sections_y > 0 {
|
||||||
|
cal_height * self.sections_y as u32
|
||||||
|
} else {
|
||||||
|
(geometry.height / cal_height) * cal_height
|
||||||
|
};
|
||||||
|
self.geometry = Geometry {
|
||||||
|
x: geometry.x,
|
||||||
|
y: geometry.y,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
};
|
||||||
|
self.geometry
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-4
@@ -4,6 +4,7 @@ use crate::{
|
|||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
|
state::Event,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -21,7 +22,8 @@ pub struct Clock {
|
|||||||
impl<'a> Clock {
|
impl<'a> Clock {
|
||||||
pub fn new(font: &'static str, size: f32) -> Clock {
|
pub fn new(font: &'static str, size: f32) -> Clock {
|
||||||
Clock {
|
Clock {
|
||||||
font, size,
|
font,
|
||||||
|
size,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
digit_width: 0,
|
digit_width: 0,
|
||||||
@@ -31,9 +33,6 @@ impl<'a> Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Clock {
|
impl<'a> Widget for Clock {
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.dirty = dirty;
|
|
||||||
}
|
|
||||||
fn get_dirty(&self) -> bool {
|
fn get_dirty(&self) -> bool {
|
||||||
self.dirty
|
self.dirty
|
||||||
}
|
}
|
||||||
@@ -42,6 +41,15 @@ impl<'a> Widget for Clock {
|
|||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
Event::NewMinute => {
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let time = Local::now().naive_local();
|
let time = Local::now().naive_local();
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
@@ -58,6 +66,7 @@ impl<'a> Widget for Clock {
|
|||||||
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
self.dirty = false;
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-4
@@ -4,6 +4,7 @@ use crate::{
|
|||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
|
state::Event,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,7 +20,8 @@ pub struct Date {
|
|||||||
impl Date {
|
impl Date {
|
||||||
pub fn new(font: &'static str, size: f32) -> Date {
|
pub fn new(font: &'static str, size: f32) -> Date {
|
||||||
Date {
|
Date {
|
||||||
font, size,
|
font,
|
||||||
|
size,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
}
|
}
|
||||||
@@ -27,9 +29,6 @@ impl Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Date {
|
impl<'a> Widget for Date {
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.dirty = dirty;
|
|
||||||
}
|
|
||||||
fn get_dirty(&self) -> bool {
|
fn get_dirty(&self) -> bool {
|
||||||
self.dirty
|
self.dirty
|
||||||
}
|
}
|
||||||
@@ -38,6 +37,15 @@ impl<'a> Widget for Date {
|
|||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
Event::NewMinute => {
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let time = Local::now().naive_local();
|
let time = Local::now().naive_local();
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
@@ -57,6 +65,7 @@ impl<'a> Widget for Date {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
self.dirty = false;
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+63
-57
@@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::{min, max, Ordering},
|
cmp::{max, min, Ordering},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
default::Default,
|
default::Default,
|
||||||
process::{exit, Command},
|
process::{exit, Command},
|
||||||
@@ -12,6 +12,7 @@ use crate::{
|
|||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
keyboard::{keysyms, KeyEvent},
|
keyboard::{keysyms, KeyEvent},
|
||||||
|
state::Event,
|
||||||
utils::desktop::{load_desktop_files, Desktop},
|
utils::desktop::{load_desktop_files, Desktop},
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
@@ -287,18 +288,17 @@ impl InterfaceWidget for Launcher {
|
|||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - line_height;
|
let mut prompt_offset = intf.geometry.height - line_height;
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
||||||
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
|
||||||
prompt_border.memset(&fg);
|
|
||||||
|
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let mut x_max = font.auto_draw_text_with_cursor(
|
let mut x_max = font
|
||||||
&mut prompt_line,
|
.auto_draw_text_with_cursor(
|
||||||
&bg,
|
&mut prompt_line,
|
||||||
&fg,
|
&bg,
|
||||||
&format!(" {}", &intf.prompt.input),
|
&fg,
|
||||||
intf.prompt.cursor + 3,
|
&format!(" {}", &intf.prompt.input),
|
||||||
)
|
intf.prompt.cursor + 3,
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -328,11 +328,17 @@ impl InterfaceWidget for Launcher {
|
|||||||
colors.push(Color::new(0.75, 0.75, 0.75, 1.0));
|
colors.push(Color::new(0.75, 0.75, 0.75, 1.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x_max = max(x_max, font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
x_max = max(
|
||||||
.unwrap());
|
x_max,
|
||||||
|
font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
x_max = max(x_max, font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
x_max = max(
|
||||||
.unwrap());
|
x_max,
|
||||||
|
font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +349,7 @@ impl InterfaceWidget for Launcher {
|
|||||||
Geometry {
|
Geometry {
|
||||||
x: intf.geometry.x,
|
x: intf.geometry.x,
|
||||||
y: intf.geometry.y + intf.geometry.height - content_height,
|
y: intf.geometry.y + intf.geometry.height - content_height,
|
||||||
width: x_max.0+1,
|
width: x_max.0 + 1,
|
||||||
height: content_height,
|
height: content_height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,19 +387,18 @@ impl InterfaceWidget for Shell {
|
|||||||
// Draw line
|
// Draw line
|
||||||
let prompt_offset = intf.geometry.height - line_height;
|
let prompt_offset = intf.geometry.height - line_height;
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
||||||
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
|
||||||
prompt_border.memset(&fg);
|
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let x_max = font.auto_draw_text_with_cursor(
|
let x_max = font
|
||||||
&mut prompt_line,
|
.auto_draw_text_with_cursor(
|
||||||
&bg,
|
&mut prompt_line,
|
||||||
&fg,
|
&bg,
|
||||||
&format!(" {}", &intf.prompt.input),
|
&fg,
|
||||||
intf.prompt.cursor + 3,
|
&format!(" {}", &intf.prompt.input),
|
||||||
)
|
intf.prompt.cursor + 3,
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -443,8 +448,6 @@ impl InterfaceWidget for Calc {
|
|||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - (line_height);
|
let mut prompt_offset = intf.geometry.height - (line_height);
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
||||||
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
|
||||||
prompt_border.memset(&fg);
|
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
@@ -518,7 +521,8 @@ impl Interface {
|
|||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
inner: InnerInterface {
|
inner: InnerInterface {
|
||||||
font, size,
|
font,
|
||||||
|
size,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
selection: 0,
|
selection: 0,
|
||||||
@@ -526,32 +530,6 @@ impl Interface {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for Interface {
|
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
|
||||||
self.inner.dirty = dirty;
|
|
||||||
}
|
|
||||||
fn get_dirty(&self) -> bool {
|
|
||||||
self.inner.dirty
|
|
||||||
}
|
|
||||||
|
|
||||||
fn geometry(&self) -> Geometry {
|
|
||||||
self.inner.geometry
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
|
||||||
match self.inner.prompt.mode {
|
|
||||||
PromptMode::Shell => self.shell.draw(&self.inner, fonts, view),
|
|
||||||
PromptMode::Normal => self.launcher.draw(&self.inner, fonts, view),
|
|
||||||
PromptMode::Calc => self.calc.draw(&self.inner, fonts, view),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
|
||||||
self.inner.geometry = geometry.clone();
|
|
||||||
self.inner.geometry
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keyboard_input(&mut self, event: &KeyEvent) {
|
fn keyboard_input(&mut self, event: &KeyEvent) {
|
||||||
if event.state != WEnum::Value(wl_keyboard::KeyState::Pressed) {
|
if event.state != WEnum::Value(wl_keyboard::KeyState::Pressed) {
|
||||||
@@ -610,8 +588,36 @@ impl Widget for Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn token_update(&mut self, token: &str) {
|
impl Widget for Interface {
|
||||||
self.launcher.next_token = Some(token.to_string());
|
fn get_dirty(&self) -> bool {
|
||||||
|
self.inner.dirty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self) -> Geometry {
|
||||||
|
self.inner.geometry
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
|
self.inner.dirty = false;
|
||||||
|
match self.inner.prompt.mode {
|
||||||
|
PromptMode::Shell => self.shell.draw(&self.inner, fonts, view),
|
||||||
|
PromptMode::Normal => self.launcher.draw(&self.inner, fonts, view),
|
||||||
|
PromptMode::Calc => self.calc.draw(&self.inner, fonts, view),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
|
self.inner.geometry = geometry.clone();
|
||||||
|
self.inner.geometry
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
Event::KeyEvent(e) => self.keyboard_input(e),
|
||||||
|
Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,7 @@
|
|||||||
mod backlight;
|
mod backlight;
|
||||||
mod bar_widget;
|
mod bar_widget;
|
||||||
mod battery;
|
mod battery;
|
||||||
|
mod calendar;
|
||||||
mod clock;
|
mod clock;
|
||||||
mod date;
|
mod date;
|
||||||
mod launcher;
|
mod launcher;
|
||||||
@@ -9,11 +10,12 @@ mod widget;
|
|||||||
|
|
||||||
pub use backlight::Backlight;
|
pub use backlight::Backlight;
|
||||||
pub use battery::Battery;
|
pub use battery::Battery;
|
||||||
|
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 line::Line;
|
pub use line::Line;
|
||||||
pub use widget::{
|
pub use widget::{
|
||||||
Geometry, HorizontalLayout, IndexedLayout, Layout, Margin, VerticalLayout, Widget,
|
Geometry, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin,
|
||||||
WidgetUpdater,
|
VerticalLayout, Widget, WidgetUpdater,
|
||||||
};
|
};
|
||||||
|
|||||||
+97
-37
@@ -1,7 +1,13 @@
|
|||||||
use std::cmp::{max, min};
|
use std::{
|
||||||
use std::fmt;
|
cmp::{max, min},
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{buffer::BufferView, fonts::FontMap, keyboard::KeyEvent};
|
use crate::{
|
||||||
|
buffer::BufferView,
|
||||||
|
fonts::FontMap,
|
||||||
|
state::{Event, State},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub struct Geometry {
|
pub struct Geometry {
|
||||||
@@ -47,38 +53,42 @@ pub trait Widget {
|
|||||||
fn get_dirty(&self) -> bool {
|
fn get_dirty(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn set_dirty(&mut self, _dirty: bool) {}
|
|
||||||
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 draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry;
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry;
|
||||||
fn keyboard_input(&mut self, _event: &KeyEvent) {}
|
fn event(&mut self, _event: &Event) {}
|
||||||
fn token_update(&mut self, _token: &str) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Layout<U> {
|
pub trait Layout {
|
||||||
fn geometry_update(
|
fn geometry_update(
|
||||||
&mut self,
|
&self,
|
||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
geometry: &Geometry,
|
geometry: &Geometry,
|
||||||
user_data: &mut U,
|
state: &mut State,
|
||||||
) -> Geometry;
|
) -> Geometry;
|
||||||
}
|
}
|
||||||
pub struct HorizontalLayout<U> {
|
pub struct HorizontalLayout {
|
||||||
pub widgets: Vec<Box<dyn Layout<U>>>,
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U> Layout<U> for HorizontalLayout<U> {
|
impl HorizontalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(HorizontalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for HorizontalLayout {
|
||||||
fn geometry_update(
|
fn geometry_update(
|
||||||
&mut self,
|
&self,
|
||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
geometry: &Geometry,
|
geometry: &Geometry,
|
||||||
user_data: &mut U,
|
state: &mut State,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let mut geo = geometry.clone();
|
let mut geo = geometry.clone();
|
||||||
let mut max_width = 0;
|
let mut max_width = 0;
|
||||||
let mut max_height = 0;
|
let mut max_height = 0;
|
||||||
for w in self.widgets.iter_mut() {
|
for w in self.widgets.iter() {
|
||||||
let result = w.geometry_update(fonts, &geo, user_data);
|
let result = w.geometry_update(fonts, &geo, state);
|
||||||
geo.x = result.x + result.width;
|
geo.x = result.x + result.width;
|
||||||
geo.width -= result.width;
|
geo.width -= result.width;
|
||||||
max_width += result.width;
|
max_width += result.width;
|
||||||
@@ -90,22 +100,28 @@ impl<U> Layout<U> for HorizontalLayout<U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VerticalLayout<U> {
|
pub struct VerticalLayout {
|
||||||
pub widgets: Vec<Box<dyn Layout<U>>>,
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U> Layout<U> for VerticalLayout<U> {
|
impl VerticalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(VerticalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for VerticalLayout {
|
||||||
fn geometry_update(
|
fn geometry_update(
|
||||||
&mut self,
|
&self,
|
||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
geometry: &Geometry,
|
geometry: &Geometry,
|
||||||
user_data: &mut U,
|
state: &mut State,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let mut geo = geometry.clone();
|
let mut geo = geometry.clone();
|
||||||
let mut max_width = 0;
|
let mut max_width = 0;
|
||||||
let mut max_height = 0;
|
let mut max_height = 0;
|
||||||
for w in self.widgets.iter_mut() {
|
for w in self.widgets.iter() {
|
||||||
let result = w.geometry_update(fonts, &geo, user_data);
|
let result = w.geometry_update(fonts, &geo, state);
|
||||||
geo.y = result.y + result.height;
|
geo.y = result.y + result.height;
|
||||||
geo.height -= result.height;
|
geo.height -= result.height;
|
||||||
max_width = max(result.width, max_width);
|
max_width = max(result.width, max_width);
|
||||||
@@ -126,28 +142,40 @@ pub struct IndexedLayout {
|
|||||||
pub widget_idx: usize,
|
pub widget_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: WidgetUpdater> Layout<U> for IndexedLayout {
|
impl IndexedLayout {
|
||||||
fn geometry_update(
|
pub fn new(widget_idx: usize) -> Box<dyn Layout> {
|
||||||
&mut self,
|
Box::new(IndexedLayout { widget_idx })
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
user_data: &mut U,
|
|
||||||
) -> Geometry {
|
|
||||||
user_data.geometry_update(self.widget_idx, fonts, geometry)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Margin<U> {
|
impl Layout for IndexedLayout {
|
||||||
pub widget: Box<dyn Layout<U>>,
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
state.geometry_update(self.widget_idx, fonts, geometry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Margin {
|
||||||
|
pub widget: Box<dyn Layout>,
|
||||||
pub margin: (u32, u32, u32, u32),
|
pub margin: (u32, u32, u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U> Layout<U> for Margin<U> {
|
impl Margin {
|
||||||
|
pub fn new(widget: Box<dyn Layout>, margin: (u32, u32, u32, u32)) -> Box<dyn Layout> {
|
||||||
|
Box::new(Margin { widget, margin })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for Margin {
|
||||||
fn geometry_update(
|
fn geometry_update(
|
||||||
&mut self,
|
&self,
|
||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
geometry: &Geometry,
|
geometry: &Geometry,
|
||||||
user_data: &mut U,
|
state: &mut State,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let geo = Geometry {
|
let geo = Geometry {
|
||||||
x: geometry.x + self.margin.0,
|
x: geometry.x + self.margin.0,
|
||||||
@@ -156,7 +184,7 @@ impl<U> Layout<U> for Margin<U> {
|
|||||||
height: geometry.height - self.margin.1 - self.margin.3,
|
height: geometry.height - self.margin.1 - self.margin.3,
|
||||||
};
|
};
|
||||||
|
|
||||||
let out = self.widget.geometry_update(fonts, &geo, user_data);
|
let out = self.widget.geometry_update(fonts, &geo, state);
|
||||||
Geometry {
|
Geometry {
|
||||||
x: out.x - self.margin.0,
|
x: out.x - self.margin.0,
|
||||||
y: out.y - self.margin.1,
|
y: out.y - self.margin.1,
|
||||||
@@ -165,3 +193,35 @@ impl<U> Layout<U> for Margin<U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InvertedHorizontalLayout {
|
||||||
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvertedHorizontalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(InvertedHorizontalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for InvertedHorizontalLayout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
let mut geo = geometry.clone();
|
||||||
|
let mut max_height = 0;
|
||||||
|
for w in self.widgets.iter() {
|
||||||
|
let mut temp_geo = geo.clone();
|
||||||
|
let temp_result = w.geometry_update(fonts, &temp_geo, state);
|
||||||
|
temp_geo.x = geo.x + (geo.width - temp_result.width);
|
||||||
|
let result = w.geometry_update(fonts, &temp_geo, state);
|
||||||
|
geo.width -= result.width;
|
||||||
|
max_height = max(result.height, max_height);
|
||||||
|
}
|
||||||
|
geo.height = max_height;
|
||||||
|
geo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user