Add calendar, refactor more
This commit is contained in:
@@ -20,7 +20,6 @@ pub struct Backlight {
|
||||
device_path: PathBuf,
|
||||
cur: u64,
|
||||
max: u64,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl Backlight {
|
||||
@@ -34,7 +33,6 @@ impl Backlight {
|
||||
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
||||
cur: 0,
|
||||
max: 0,
|
||||
dirty: false,
|
||||
};
|
||||
|
||||
dev.update();
|
||||
@@ -43,12 +41,6 @@ impl 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 {
|
||||
"backlight"
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ use crate::{
|
||||
};
|
||||
|
||||
pub trait BarWidgetImpl {
|
||||
fn get_dirty(&self) -> bool;
|
||||
fn set_dirty(&mut self, dirty: bool);
|
||||
fn get_dirty(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn name(&self) -> &'static str;
|
||||
fn value(&self) -> f32;
|
||||
fn color(&self) -> Color;
|
||||
@@ -27,7 +28,9 @@ impl BarWidget {
|
||||
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, font: &'static str, size: f32) -> BarWidget {
|
||||
BarWidget {
|
||||
geometry: Default::default(),
|
||||
inner_widget, font, size,
|
||||
inner_widget,
|
||||
font,
|
||||
size,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,10 +44,6 @@ impl Widget for BarWidget {
|
||||
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 {
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
let fg = Color::new(1., 1., 1., 1.);
|
||||
|
||||
+15
-14
@@ -4,8 +4,6 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use calloop::ping::Ping;
|
||||
|
||||
use dbus::blocking::{
|
||||
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
|
||||
LocalConnection,
|
||||
@@ -13,6 +11,7 @@ use dbus::blocking::{
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
state::{Event, Events},
|
||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||
};
|
||||
|
||||
@@ -28,9 +27,10 @@ enum UpowerBatteryState {
|
||||
struct InnerBattery {
|
||||
value: f32,
|
||||
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()
|
||||
.name("battmon".to_string())
|
||||
.spawn(move || {
|
||||
@@ -84,11 +84,15 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, ping: Ping) {
|
||||
6 => UpowerBatteryState::Discharging,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
};
|
||||
ping.ping();
|
||||
inner.dirty = true;
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
}
|
||||
"Percentage" => {
|
||||
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 {
|
||||
inner: Arc<Mutex<InnerBattery>>,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
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 {
|
||||
inner: Arc::new(Mutex::new(InnerBattery {
|
||||
value: 0.,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl BarWidgetImpl for Battery {
|
||||
fn get_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
fn set_dirty(&mut self, dirty: bool) {
|
||||
self.dirty = dirty
|
||||
self.inner.lock().unwrap().dirty
|
||||
}
|
||||
fn name(&self) -> &'static str {
|
||||
"battery"
|
||||
}
|
||||
fn value(&self) -> f32 {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.dirty = false;
|
||||
inner.value
|
||||
}
|
||||
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,
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
state::Event,
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
|
||||
@@ -21,7 +22,8 @@ pub struct Clock {
|
||||
impl<'a> Clock {
|
||||
pub fn new(font: &'static str, size: f32) -> Clock {
|
||||
Clock {
|
||||
font, size,
|
||||
font,
|
||||
size,
|
||||
dirty: true,
|
||||
geometry: Default::default(),
|
||||
digit_width: 0,
|
||||
@@ -31,9 +33,6 @@ impl<'a> Clock {
|
||||
}
|
||||
|
||||
impl<'a> Widget for Clock {
|
||||
fn set_dirty(&mut self, dirty: bool) {
|
||||
self.dirty = dirty;
|
||||
}
|
||||
fn get_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
@@ -42,6 +41,15 @@ impl<'a> Widget for Clock {
|
||||
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();
|
||||
let fg = Color::new(1., 1., 1., 1.);
|
||||
@@ -58,6 +66,7 @@ impl<'a> Widget for Clock {
|
||||
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
||||
)
|
||||
.unwrap();
|
||||
self.dirty = false;
|
||||
self.geometry
|
||||
}
|
||||
|
||||
|
||||
+13
-4
@@ -4,6 +4,7 @@ use crate::{
|
||||
buffer::BufferView,
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
state::Event,
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
|
||||
@@ -19,7 +20,8 @@ pub struct Date {
|
||||
impl Date {
|
||||
pub fn new(font: &'static str, size: f32) -> Date {
|
||||
Date {
|
||||
font, size,
|
||||
font,
|
||||
size,
|
||||
dirty: true,
|
||||
geometry: Default::default(),
|
||||
}
|
||||
@@ -27,9 +29,6 @@ impl Date {
|
||||
}
|
||||
|
||||
impl<'a> Widget for Date {
|
||||
fn set_dirty(&mut self, dirty: bool) {
|
||||
self.dirty = dirty;
|
||||
}
|
||||
fn get_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
@@ -38,6 +37,15 @@ impl<'a> Widget for Date {
|
||||
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();
|
||||
let fg = Color::new(1., 1., 1., 1.);
|
||||
@@ -57,6 +65,7 @@ impl<'a> Widget for Date {
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
self.dirty = false;
|
||||
self.geometry
|
||||
}
|
||||
|
||||
|
||||
+63
-57
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
cmp::{min, max, Ordering},
|
||||
cmp::{max, min, Ordering},
|
||||
collections::HashMap,
|
||||
default::Default,
|
||||
process::{exit, Command},
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
keyboard::{keysyms, KeyEvent},
|
||||
state::Event,
|
||||
utils::desktop::{load_desktop_files, Desktop},
|
||||
widgets::{Geometry, Widget},
|
||||
};
|
||||
@@ -287,18 +288,17 @@ impl InterfaceWidget for Launcher {
|
||||
// Draw line
|
||||
let mut prompt_offset = intf.geometry.height - line_height;
|
||||
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 mut x_max = font.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
&bg,
|
||||
&fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
let mut x_max = font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
&bg,
|
||||
&fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
||||
.unwrap();
|
||||
@@ -328,11 +328,17 @@ impl InterfaceWidget for Launcher {
|
||||
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)
|
||||
.unwrap());
|
||||
x_max = max(
|
||||
x_max,
|
||||
font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
x_max = max(x_max, font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
||||
.unwrap());
|
||||
x_max = max(
|
||||
x_max,
|
||||
font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +349,7 @@ impl InterfaceWidget for Launcher {
|
||||
Geometry {
|
||||
x: intf.geometry.x,
|
||||
y: intf.geometry.y + intf.geometry.height - content_height,
|
||||
width: x_max.0+1,
|
||||
width: x_max.0 + 1,
|
||||
height: content_height,
|
||||
}
|
||||
}
|
||||
@@ -381,19 +387,18 @@ impl InterfaceWidget for Shell {
|
||||
// Draw line
|
||||
let prompt_offset = intf.geometry.height - line_height;
|
||||
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
|
||||
let font = fonts.get_font(intf.font, intf.size);
|
||||
let x_max = font.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
&bg,
|
||||
&fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
let x_max = font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
&bg,
|
||||
&fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
||||
.unwrap();
|
||||
|
||||
@@ -443,8 +448,6 @@ impl InterfaceWidget for Calc {
|
||||
// Draw line
|
||||
let mut prompt_offset = intf.geometry.height - (line_height);
|
||||
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
|
||||
let font = fonts.get_font(intf.font, intf.size);
|
||||
@@ -518,7 +521,8 @@ impl Interface {
|
||||
result: None,
|
||||
},
|
||||
inner: InnerInterface {
|
||||
font, size,
|
||||
font,
|
||||
size,
|
||||
dirty: false,
|
||||
geometry: Default::default(),
|
||||
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) {
|
||||
if event.state != WEnum::Value(wl_keyboard::KeyState::Pressed) {
|
||||
@@ -610,8 +588,36 @@ impl Widget for Interface {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn token_update(&mut self, token: &str) {
|
||||
self.launcher.next_token = Some(token.to_string());
|
||||
impl Widget for Interface {
|
||||
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 bar_widget;
|
||||
mod battery;
|
||||
mod calendar;
|
||||
mod clock;
|
||||
mod date;
|
||||
mod launcher;
|
||||
@@ -9,11 +10,12 @@ mod widget;
|
||||
|
||||
pub use backlight::Backlight;
|
||||
pub use battery::Battery;
|
||||
pub use calendar::Calendar;
|
||||
pub use clock::Clock;
|
||||
pub use date::Date;
|
||||
pub use launcher::Interface;
|
||||
pub use line::Line;
|
||||
pub use widget::{
|
||||
Geometry, HorizontalLayout, IndexedLayout, Layout, Margin, VerticalLayout, Widget,
|
||||
WidgetUpdater,
|
||||
Geometry, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin,
|
||||
VerticalLayout, Widget, WidgetUpdater,
|
||||
};
|
||||
|
||||
+97
-37
@@ -1,7 +1,13 @@
|
||||
use std::cmp::{max, min};
|
||||
use std::fmt;
|
||||
use std::{
|
||||
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)]
|
||||
pub struct Geometry {
|
||||
@@ -47,38 +53,42 @@ pub trait Widget {
|
||||
fn get_dirty(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_dirty(&mut self, _dirty: bool) {}
|
||||
fn geometry(&self) -> Geometry;
|
||||
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry;
|
||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry;
|
||||
fn keyboard_input(&mut self, _event: &KeyEvent) {}
|
||||
fn token_update(&mut self, _token: &str) {}
|
||||
fn event(&mut self, _event: &Event) {}
|
||||
}
|
||||
|
||||
pub trait Layout<U> {
|
||||
pub trait Layout {
|
||||
fn geometry_update(
|
||||
&mut self,
|
||||
&self,
|
||||
fonts: &mut FontMap,
|
||||
geometry: &Geometry,
|
||||
user_data: &mut U,
|
||||
state: &mut State,
|
||||
) -> Geometry;
|
||||
}
|
||||
pub struct HorizontalLayout<U> {
|
||||
pub widgets: Vec<Box<dyn Layout<U>>>,
|
||||
pub struct HorizontalLayout {
|
||||
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(
|
||||
&mut self,
|
||||
&self,
|
||||
fonts: &mut FontMap,
|
||||
geometry: &Geometry,
|
||||
user_data: &mut U,
|
||||
state: &mut State,
|
||||
) -> Geometry {
|
||||
let mut geo = geometry.clone();
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
for w in self.widgets.iter_mut() {
|
||||
let result = w.geometry_update(fonts, &geo, user_data);
|
||||
for w in self.widgets.iter() {
|
||||
let result = w.geometry_update(fonts, &geo, state);
|
||||
geo.x = result.x + result.width;
|
||||
geo.width -= result.width;
|
||||
max_width += result.width;
|
||||
@@ -90,22 +100,28 @@ impl<U> Layout<U> for HorizontalLayout<U> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VerticalLayout<U> {
|
||||
pub widgets: Vec<Box<dyn Layout<U>>>,
|
||||
pub struct VerticalLayout {
|
||||
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(
|
||||
&mut self,
|
||||
&self,
|
||||
fonts: &mut FontMap,
|
||||
geometry: &Geometry,
|
||||
user_data: &mut U,
|
||||
state: &mut State,
|
||||
) -> Geometry {
|
||||
let mut geo = geometry.clone();
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
for w in self.widgets.iter_mut() {
|
||||
let result = w.geometry_update(fonts, &geo, user_data);
|
||||
for w in self.widgets.iter() {
|
||||
let result = w.geometry_update(fonts, &geo, state);
|
||||
geo.y = result.y + result.height;
|
||||
geo.height -= result.height;
|
||||
max_width = max(result.width, max_width);
|
||||
@@ -126,28 +142,40 @@ pub struct IndexedLayout {
|
||||
pub widget_idx: usize,
|
||||
}
|
||||
|
||||
impl<U: WidgetUpdater> Layout<U> for IndexedLayout {
|
||||
fn geometry_update(
|
||||
&mut self,
|
||||
fonts: &mut FontMap,
|
||||
geometry: &Geometry,
|
||||
user_data: &mut U,
|
||||
) -> Geometry {
|
||||
user_data.geometry_update(self.widget_idx, fonts, geometry)
|
||||
impl IndexedLayout {
|
||||
pub fn new(widget_idx: usize) -> Box<dyn Layout> {
|
||||
Box::new(IndexedLayout { widget_idx })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Margin<U> {
|
||||
pub widget: Box<dyn Layout<U>>,
|
||||
impl Layout for IndexedLayout {
|
||||
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),
|
||||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
&self,
|
||||
fonts: &mut FontMap,
|
||||
geometry: &Geometry,
|
||||
user_data: &mut U,
|
||||
state: &mut State,
|
||||
) -> Geometry {
|
||||
let geo = Geometry {
|
||||
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,
|
||||
};
|
||||
|
||||
let out = self.widget.geometry_update(fonts, &geo, user_data);
|
||||
let out = self.widget.geometry_update(fonts, &geo, state);
|
||||
Geometry {
|
||||
x: out.x - self.margin.0,
|
||||
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