Σ:3
This commit is contained in:
parent
27f8cc3ab8
commit
9bf4c44aa2
4 changed files with 41 additions and 236 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::widget::{Message, PanelWidget};
|
use crate::widget::{Message, PanelWidget};
|
||||||
use crate::widgets::battery::BatteryWidget;
|
use crate::widgets::battery::BatteryWidget;
|
||||||
use crate::widgets::clock::ClockWidget;
|
use crate::widgets::clock::ClockWidget;
|
||||||
|
use crate::widgets::focused_window::FocusedWindowWidget;
|
||||||
use crate::widgets::powerbutton::ShutdownWidget;
|
use crate::widgets::powerbutton::ShutdownWidget;
|
||||||
use crate::widgets::spacer::Spacer;
|
use crate::widgets::spacer::Spacer;
|
||||||
|
|
||||||
use iced::Color;
|
use iced::Color;
|
||||||
use iced::Element;
|
use iced::Element;
|
||||||
use iced::Subscription;
|
use iced::Subscription;
|
||||||
|
|
@ -24,6 +24,7 @@ impl App {
|
||||||
Box::new(ShutdownWidget::new()),
|
Box::new(ShutdownWidget::new()),
|
||||||
Box::new(Spacer::new(iced::Length::Fill)),
|
Box::new(Spacer::new(iced::Length::Fill)),
|
||||||
Box::new(BatteryWidget::new()),
|
Box::new(BatteryWidget::new()),
|
||||||
|
Box::new(FocusedWindowWidget::new()),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
243
src/main.rs
243
src/main.rs
|
|
@ -1,28 +1,22 @@
|
||||||
use iced::Color;
|
|
||||||
use iced::Element;
|
|
||||||
use iced::Task;
|
|
||||||
use iced::widget::button;
|
|
||||||
use iced::widget::container;
|
|
||||||
use iced::widget::row;
|
|
||||||
use iced::widget::text;
|
|
||||||
use iced_layershell::daemon;
|
use iced_layershell::daemon;
|
||||||
use iced_layershell::reexport::Anchor;
|
use iced_layershell::reexport::Anchor;
|
||||||
use iced_layershell::reexport::NewLayerShellSettings;
|
|
||||||
use iced_layershell::settings::LayerShellSettings;
|
use iced_layershell::settings::LayerShellSettings;
|
||||||
use iced_layershell::settings::Settings;
|
use iced_layershell::settings::Settings;
|
||||||
use iced_layershell::to_layer_message;
|
|
||||||
use std::collections::HashMap;
|
mod app;
|
||||||
use std::time::Duration;
|
mod widget;
|
||||||
|
mod widgets;
|
||||||
|
use app::App;
|
||||||
|
|
||||||
pub fn main() -> Result<(), iced_layershell::Error> {
|
pub fn main() -> Result<(), iced_layershell::Error> {
|
||||||
daemon(App::default, App::name, App::update, App::view)
|
daemon(App::new, App::name, App::update, App::view)
|
||||||
.style(App::style)
|
.style(App::style)
|
||||||
.theme(App::theme)
|
.theme(App::theme)
|
||||||
.subscription(App::subscription)
|
.subscription(App::subscription)
|
||||||
.settings(Settings {
|
.settings(Settings {
|
||||||
layer_settings: LayerShellSettings {
|
layer_settings: LayerShellSettings {
|
||||||
size: Some((0, 32)),
|
size: Some((0, App::WINDOW_HEIGHT)),
|
||||||
exclusive_zone: 32,
|
exclusive_zone: App::WINDOW_HEIGHT as i32,
|
||||||
anchor: Anchor::Top | Anchor::Left | Anchor::Right,
|
anchor: Anchor::Top | Anchor::Left | Anchor::Right,
|
||||||
start_mode: iced_layershell::settings::StartMode::AllScreens,
|
start_mode: iced_layershell::settings::StartMode::AllScreens,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -32,224 +26,3 @@ pub fn main() -> Result<(), iced_layershell::Error> {
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App {
|
|
||||||
popups: HashMap<iced::window::Id, PopupKind>,
|
|
||||||
power_off_widget: PowerOffWidget,
|
|
||||||
time_widget: TimeWidget,
|
|
||||||
battery_widget: BatteryWidget,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PopupKind {
|
|
||||||
PowerOff,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for App {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut output = Self {
|
|
||||||
popups: HashMap::new(),
|
|
||||||
power_off_widget: PowerOffWidget(None, false),
|
|
||||||
time_widget: Default::default(),
|
|
||||||
battery_widget: Default::default(),
|
|
||||||
};
|
|
||||||
let _ = output.update(Message::Clock);
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
fn name() -> String {
|
|
||||||
"wayland_panel".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close_popup(&mut self, id: iced::window::Id) -> Task<Message> {
|
|
||||||
self.popups.remove(&id);
|
|
||||||
Task::done(Message::RemoveWindow(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self, id: iced::window::Id) -> Element<'_, Message> {
|
|
||||||
if let Some(kind) = self.popups.get(&id) {
|
|
||||||
return match kind {
|
|
||||||
PopupKind::PowerOff => container(
|
|
||||||
row![
|
|
||||||
text("Shut down?"),
|
|
||||||
button("✓").on_press(Message::PowerOffConfirm),
|
|
||||||
button("✗").on_press(Message::PowerOffCancel),
|
|
||||||
]
|
|
||||||
.spacing(8)
|
|
||||||
.align_y(iced::Alignment::Center),
|
|
||||||
)
|
|
||||||
.center(iced::Length::Fill)
|
|
||||||
.into(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// default: the bar
|
|
||||||
let content = row![
|
|
||||||
self.time_widget.view(),
|
|
||||||
iced::widget::space().width(iced::Length::Fill),
|
|
||||||
self.power_off_widget.view(),
|
|
||||||
iced::widget::space().width(iced::Length::Fill),
|
|
||||||
self.battery_widget.view(),
|
|
||||||
]
|
|
||||||
.padding(iced::Padding::from([0, 5]))
|
|
||||||
.height(iced::Length::Fill)
|
|
||||||
.width(iced::Length::Fill)
|
|
||||||
.align_y(iced::Alignment::Center);
|
|
||||||
|
|
||||||
container(content).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Task<Message> {
|
|
||||||
match message {
|
|
||||||
Message::Clock => {
|
|
||||||
self.time_widget.update();
|
|
||||||
self.battery_widget.update();
|
|
||||||
|
|
||||||
Task::none()
|
|
||||||
}
|
|
||||||
Message::PowerOff => {
|
|
||||||
let id = iced::window::Id::unique();
|
|
||||||
self.popups.insert(id, PopupKind::PowerOff);
|
|
||||||
|
|
||||||
self.power_off_widget.0 = Some(id);
|
|
||||||
|
|
||||||
Task::done(Message::NewLayerShell {
|
|
||||||
settings: NewLayerShellSettings {
|
|
||||||
size: Some((220, 40)),
|
|
||||||
anchor: Anchor::Top,
|
|
||||||
layer: iced_layershell::reexport::Layer::Overlay,
|
|
||||||
keyboard_interactivity:
|
|
||||||
iced_layershell::reexport::KeyboardInteractivity::OnDemand,
|
|
||||||
exclusive_zone: None,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Message::PowerOffConfirm => {
|
|
||||||
std::process::Command::new("poweroff").spawn().ok();
|
|
||||||
Task::none()
|
|
||||||
}
|
|
||||||
Message::PowerOffCancel => self.close_popup(self.power_off_widget.0.unwrap()),
|
|
||||||
_ => Task::none(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn style(&self, theme: &iced::Theme) -> iced::theme::Style {
|
|
||||||
iced::theme::Style {
|
|
||||||
background_color: Color::TRANSPARENT,
|
|
||||||
text_color: theme.palette().text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn theme(&self, _id: iced::window::Id) -> iced::Theme {
|
|
||||||
iced::Theme::GruvboxDark
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subscription(&self) -> iced::Subscription<Message> {
|
|
||||||
iced::time::every(Duration::from_secs(1)).map(|_| Message::Clock)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait PanelWidget {
|
|
||||||
fn update(&mut self);
|
|
||||||
fn view(&self) -> Element<'_, Message>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct BatteryWidget {
|
|
||||||
battery: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PanelWidget for BatteryWidget {
|
|
||||||
fn update(&mut self) {
|
|
||||||
let file_content = std::fs::read_to_string(std::path::Path::new(
|
|
||||||
"/sys/class/power_supply/BAT0/capacity",
|
|
||||||
));
|
|
||||||
|
|
||||||
let Ok(file_string) = file_content else {
|
|
||||||
self.battery = None;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let file_string = file_string.trim();
|
|
||||||
|
|
||||||
let Ok(value) = file_string.parse::<usize>() else {
|
|
||||||
self.battery = None;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.battery = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Message> {
|
|
||||||
match self.battery {
|
|
||||||
Some(battery) => text!("{} {}", battery.to_string(), Self::get_icon(battery)),
|
|
||||||
None => text(""),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BatteryWidget {
|
|
||||||
fn get_icon(battery: usize) -> &'static str {
|
|
||||||
match battery {
|
|
||||||
0..6 => "",
|
|
||||||
6..11 => "",
|
|
||||||
11..21 => "",
|
|
||||||
21..31 => "",
|
|
||||||
31..41 => "",
|
|
||||||
41..51 => "",
|
|
||||||
51..61 => "",
|
|
||||||
61..71 => "",
|
|
||||||
71..81 => "",
|
|
||||||
81..91 => "",
|
|
||||||
91..101 => "",
|
|
||||||
_ => "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct TimeWidget {
|
|
||||||
current_time: chrono::DateTime<chrono::Local>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PanelWidget for TimeWidget {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.current_time = chrono::Local::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Message> {
|
|
||||||
text!("{}", self.current_time.format("%H:%m")).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct PowerOffWidget(Option<iced::window::Id>, bool);
|
|
||||||
|
|
||||||
impl PanelWidget for PowerOffWidget {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.1 = !self.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Message> {
|
|
||||||
button("⏻")
|
|
||||||
.on_press(if self.1 {
|
|
||||||
Message::PowerOffCancel
|
|
||||||
} else {
|
|
||||||
Message::PowerOff
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[to_layer_message(multi)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Message {
|
|
||||||
Clock,
|
|
||||||
PowerOff,
|
|
||||||
PowerOffConfirm,
|
|
||||||
PowerOffCancel,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
30
src/widgets/focused_window.rs
Normal file
30
src/widgets/focused_window.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
use iced::{Subscription, Task};
|
||||||
|
use wayland_protocols_wlr::foreign_toplevel;
|
||||||
|
|
||||||
|
use crate::widget::PanelWidget;
|
||||||
|
|
||||||
|
pub struct FocusedWindowWidget {
|
||||||
|
focused_window: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FocusedWindowWidget {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
focused_window: foreign_toplevel::v1::client::zwlr_foreign_toplevel_manager_v1::Event,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PanelWidget for FocusedWindowWidget {
|
||||||
|
fn update(&mut self, _message: &crate::widget::Message) -> iced::Task<crate::widget::Message> {
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscribe(&self) -> iced::Subscription<crate::widget::Message> {
|
||||||
|
Subscription::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, _id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> {
|
||||||
|
iced::widget::text!("{}", self.focused_window).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod battery;
|
pub mod battery;
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
|
pub mod focused_window;
|
||||||
pub mod powerbutton;
|
pub mod powerbutton;
|
||||||
pub mod spacer;
|
pub mod spacer;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue