use serde_json::Value as JsonValue;
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::compositor::Plane;
use crate::error::DraconError;
use crate::framework::command::{BoundCommand, ParsedOutput};
use crate::input::event::{KeyEvent, MouseEventKind};
use ratatui::layout::Rect;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct WidgetId(pub usize);
impl WidgetId {
pub fn new(id: usize) -> Self {
Self(id)
}
pub fn default_id() -> Self {
Self(0)
}
pub fn next() -> Self {
static COUNTER: AtomicUsize = AtomicUsize::new(1);
Self(COUNTER.fetch_add(1, Ordering::Relaxed))
}
}
pub trait Widget {
fn id(&self) -> WidgetId;
fn area(&self) -> Rect;
fn set_area(&mut self, area: Rect);
fn focusable(&self) -> bool {
true
}
fn z_index(&self) -> u16 {
0
}
fn needs_render(&self) -> bool {
true
}
fn mark_dirty(&mut self) {}
fn clear_dirty(&mut self) {}
fn cursor_position(&self) -> Option<(u16, u16)> {
None
}
fn render(&self, area: Rect) -> Plane;
fn draw_to(&mut self, target: &mut Plane, x: u16, y: u16) {
let area = self.area();
let plane = self.render(area);
target.blit_from(&plane, x, y);
}
fn on_focus(&mut self) {}
fn on_blur(&mut self) {}
fn on_mount(&mut self) {}
fn on_unmount(&mut self) {}
fn set_id(&mut self, _id: WidgetId) {}
fn on_theme_change(&mut self, _theme: &crate::framework::theme::Theme) {}
fn current_theme(&self) -> Option<crate::framework::theme::Theme> {
None
}
fn handle_key(&mut self, _key: KeyEvent) -> bool {
false
}
fn handle_mouse(&mut self, _kind: MouseEventKind, _col: u16, _row: u16) -> bool {
false
}
fn commands(&self) -> Vec<BoundCommand> {
Vec::new()
}
fn apply_command_output(&mut self, _output: &ParsedOutput) {}
}
#[cfg(feature = "async")]
#[allow(async_fn_in_trait)]
pub trait AsyncWidget: Widget {
async fn on_mount_async(&mut self) {}
async fn on_unmount_async(&mut self) {}
}
pub trait WidgetState {
fn state_id(&self) -> Option<&str>;
fn to_json(&self) -> JsonValue;
fn apply_json(&mut self, json: &JsonValue) -> Result<(), DraconError>;
}