use super::{Widget, WidgetAlignment, WidgetClickResult, WidgetContext};
use crate::rendering::{Theme, VideoBuffer};
#[cfg(feature = "battery")]
use crate::rendering::Cell;
#[cfg(feature = "battery")]
use crate::ui::ui_render::battery_support::{BatteryInfo, get_battery_color, get_battery_info};
#[cfg(feature = "battery")]
use crate::window::manager::FocusState;
#[cfg(feature = "battery")]
use crossterm::style::Color;
pub struct BatteryWidget {
hovered: bool,
#[cfg(feature = "battery")]
cached_info: Option<BatteryInfo>,
#[cfg(not(feature = "battery"))]
_phantom: (),
}
impl BatteryWidget {
pub fn new() -> Self {
Self {
hovered: false,
#[cfg(feature = "battery")]
cached_info: None,
#[cfg(not(feature = "battery"))]
_phantom: (),
}
}
pub fn is_hovered(&self) -> bool {
self.hovered
}
#[cfg(feature = "battery")]
fn get_battery_icon(percentage: u8, charset: &crate::rendering::Charset) -> char {
if percentage >= 75 {
charset.battery_full } else if percentage >= 50 {
charset.battery_high } else if percentage >= 25 {
charset.battery_medium } else if percentage >= 10 {
charset.battery_low } else {
charset.battery_critical }
}
#[cfg(feature = "battery")]
fn render_widget(
&self,
buffer: &mut VideoBuffer,
x: u16,
theme: &Theme,
info: &BatteryInfo,
ctx: &WidgetContext,
) {
let pct = info.percentage;
let is_charging = info.is_charging;
let battery_color = get_battery_color(pct, is_charging);
let charset = ctx.charset;
let bg_color = match ctx.focus {
FocusState::Desktop | FocusState::Topbar => theme.topbar_bg_focused,
FocusState::Window(_) => theme.topbar_bg_unfocused,
};
let fg_color = theme.window_border_unfocused_fg;
let charging_icon = charset.battery_charging;
let charging_color = Color::Yellow;
let battery_icon = Self::get_battery_icon(pct, charset);
let mut current_x = x;
buffer.set(current_x, 0, Cell::new_unchecked(' ', fg_color, bg_color));
current_x += 1;
let pct_str = format!("{:>3}%", pct);
for ch in pct_str.chars() {
buffer.set(
current_x,
0,
Cell::new_unchecked(ch, battery_color, bg_color),
);
current_x += 1;
}
buffer.set(current_x, 0, Cell::new_unchecked(' ', fg_color, bg_color));
current_x += 1;
if is_charging {
buffer.set(
current_x,
0,
Cell::new_unchecked(charging_icon, charging_color, bg_color),
);
current_x += 1;
}
buffer.set(current_x, 0, Cell::new_unchecked('[', fg_color, bg_color));
current_x += 1;
let filled_count = ((pct as f32 / 100.0) * 3.0).ceil() as usize;
for i in 0..3 {
let ch = if i < filled_count { battery_icon } else { ' ' };
let fg = if i < filled_count {
battery_color
} else {
Color::DarkGrey
};
buffer.set(current_x, 0, Cell::new_unchecked(ch, fg, bg_color));
current_x += 1;
}
buffer.set(current_x, 0, Cell::new_unchecked(']', fg_color, bg_color));
current_x += 1;
buffer.set(current_x, 0, Cell::new_unchecked('+', fg_color, bg_color));
current_x += 1;
buffer.set(current_x, 0, Cell::new_unchecked(' ', fg_color, bg_color));
}
}
impl Default for BatteryWidget {
fn default() -> Self {
Self::new()
}
}
impl Widget for BatteryWidget {
fn width(&self) -> u16 {
#[cfg(feature = "battery")]
{
if let Some(ref info) = self.cached_info {
if info.is_charging {
14 } else {
13 }
} else {
13
}
}
#[cfg(not(feature = "battery"))]
{
0
}
}
fn render(&self, buffer: &mut VideoBuffer, x: u16, theme: &Theme, ctx: &WidgetContext) {
#[cfg(feature = "battery")]
if let Some(ref info) = self.cached_info {
self.render_widget(buffer, x, theme, info, ctx);
}
#[cfg(not(feature = "battery"))]
{
let _ = (buffer, x, theme, ctx);
}
}
fn is_visible(&self, _ctx: &WidgetContext) -> bool {
#[cfg(feature = "battery")]
{
self.cached_info.is_some()
}
#[cfg(not(feature = "battery"))]
{
false
}
}
fn contains(&self, point_x: u16, point_y: u16, widget_x: u16) -> bool {
point_y == 0 && point_x >= widget_x && point_x < widget_x + self.width()
}
fn update_hover(&mut self, mouse_x: u16, mouse_y: u16, widget_x: u16) {
self.hovered = self.contains(mouse_x, mouse_y, widget_x);
}
fn handle_click(&mut self, _mouse_x: u16, _mouse_y: u16, _widget_x: u16) -> WidgetClickResult {
WidgetClickResult::NotHandled
}
fn reset_state(&mut self) {
self.hovered = false;
}
fn update(&mut self, _ctx: &WidgetContext) {
#[cfg(feature = "battery")]
{
self.cached_info = get_battery_info();
}
}
fn alignment(&self) -> WidgetAlignment {
WidgetAlignment::Right
}
}