use crate::theme::Theme;
use crate::video_buffer::{Cell, VideoBuffer};
#[derive(Debug, Clone, PartialEq)]
pub enum ButtonState {
Normal,
Hovered,
Pressed,
}
#[derive(Debug, Clone)]
pub struct Button {
pub x: u16,
pub y: u16,
pub label: String,
pub state: ButtonState,
pub enabled: bool,
}
impl Button {
pub fn new(x: u16, y: u16, label: String) -> Self {
Self {
x,
y,
label,
state: ButtonState::Normal,
enabled: true,
}
}
pub fn width(&self) -> u16 {
(self.label.len() as u16) + 4 }
pub fn contains(&self, x: u16, y: u16) -> bool {
if !self.enabled {
return false;
}
x >= self.x && x < self.x + self.width() && y == self.y
}
pub fn set_state(&mut self, state: ButtonState) {
self.state = state;
}
pub fn render(&self, buffer: &mut VideoBuffer, theme: &Theme) {
if !self.enabled {
return;
}
let (fg_color, bg_color) = match self.state {
ButtonState::Normal => (theme.button_normal_fg, theme.button_normal_bg),
ButtonState::Hovered => (theme.button_hovered_fg, theme.button_hovered_bg),
ButtonState::Pressed => (theme.button_pressed_fg, theme.button_pressed_bg),
};
let mut current_x = self.x;
buffer.set(current_x, self.y, Cell::new('[', fg_color, bg_color));
current_x += 1;
buffer.set(current_x, self.y, Cell::new(' ', fg_color, bg_color));
current_x += 1;
for ch in self.label.chars() {
buffer.set(current_x, self.y, Cell::new(ch, fg_color, bg_color));
current_x += 1;
}
buffer.set(current_x, self.y, Cell::new(' ', fg_color, bg_color));
current_x += 1;
buffer.set(current_x, self.y, Cell::new(']', fg_color, bg_color));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_button_width() {
let button = Button::new(0, 0, "Test".to_string());
assert_eq!(button.width(), 8); }
#[test]
fn test_button_contains() {
let button = Button::new(5, 10, "Click".to_string());
assert!(button.contains(5, 10)); assert!(button.contains(8, 10)); assert!(button.contains(13, 10)); assert!(!button.contains(14, 10)); assert!(!button.contains(4, 10)); assert!(!button.contains(5, 11)); }
}