use crate::dirty::Dirty;
use crate::event::{Command, Event, EventPhase};
use crate::geom::{Rect, Size};
use crate::layout::Constraint;
use crate::node::Node;
use crate::render::RenderCx;
use crate::style::Style;
pub trait Component {
fn render(&self, cx: &mut RenderCx);
fn event(&mut self, _event: &Event, _cx: &mut EventCx) {}
fn style(&self) -> Style {
Style::default()
}
fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
Size {
width: constraint.max.width,
height: 1,
}
}
fn layout(&mut self, _rect: Rect, _cx: &mut LayoutCx) {}
fn mount(&mut self, _cx: &mut EventCx) {}
fn unmount(&mut self, _cx: &mut EventCx) {}
fn update(&mut self, _cx: &mut EventCx) {}
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
.split("::")
.last()
.unwrap_or("Unknown")
}
fn id(&self) -> Option<&str> {
None
}
fn class(&self) -> Option<&str> {
None
}
fn focusable(&self) -> bool {
true
}
fn for_each_child(&self, _f: &mut dyn FnMut(&Node)) {}
fn for_each_child_mut(&mut self, _f: &mut dyn FnMut(&mut Node)) {}
}
pub struct EventCx<'a> {
pub(crate) node_dirty: &'a mut Dirty,
pub(crate) global_dirty: &'a mut Dirty,
pub(crate) quit: &'a mut bool,
pub(crate) phase: EventPhase,
pub(crate) propagation_stopped: &'a mut bool,
pub(crate) task_sender: Option<std::sync::mpsc::Sender<String>>,
}
impl<'a> EventCx<'a> {
pub(crate) fn new(
node_dirty: &'a mut Dirty,
global_dirty: &'a mut Dirty,
quit: &'a mut bool,
phase: EventPhase,
propagation_stopped: &'a mut bool,
) -> Self {
Self {
node_dirty,
global_dirty,
quit,
phase,
propagation_stopped,
task_sender: None,
}
}
pub(crate) fn with_task_sender(
node_dirty: &'a mut Dirty,
global_dirty: &'a mut Dirty,
quit: &'a mut bool,
phase: EventPhase,
propagation_stopped: &'a mut bool,
task_sender: Option<std::sync::mpsc::Sender<String>>,
) -> Self {
Self {
node_dirty,
global_dirty,
quit,
phase,
propagation_stopped,
task_sender,
}
}
pub fn phase(&self) -> EventPhase {
self.phase
}
pub fn stop_propagation(&mut self) {
*self.propagation_stopped = true;
}
pub fn invalidate_paint(&mut self) {
*self.node_dirty |= Dirty::PAINT;
*self.global_dirty |= Dirty::PAINT;
}
pub fn invalidate_layout(&mut self) {
*self.node_dirty |= Dirty::LAYOUT | Dirty::PAINT;
*self.global_dirty |= Dirty::LAYOUT | Dirty::PAINT;
}
pub fn invalidate(&mut self) {
self.invalidate_layout();
}
pub fn invalidate_tree(&mut self) {
*self.node_dirty |= Dirty::TREE | Dirty::LAYOUT | Dirty::PAINT;
*self.global_dirty |= Dirty::TREE | Dirty::LAYOUT | Dirty::PAINT;
}
pub fn copy_to_clipboard(&self, text: &str) {
use std::io::Write;
let seq = crate::clipboard::copy_to_clipboard_sequence(text);
let _ = std::io::stdout().write_all(seq.as_bytes());
let _ = std::io::stdout().flush();
}
pub fn quit(&mut self) {
*self.quit = true;
}
pub fn dispatch(&mut self, cmd: Command) {
crate::runtime::COMMAND_QUEUE.with(|q| {
q.borrow_mut().push(cmd);
});
}
pub fn toggle_debug() {
crate::runtime::DEBUG_MODE.with(|d| {
let current = *d.borrow();
*d.borrow_mut() = !current;
});
}
pub fn spawn<F>(&mut self, task: F)
where
F: FnOnce() -> String + Send + 'static,
{
if let Some(tx) = self.task_sender.clone() {
std::thread::spawn(move || {
let result = task();
let _ = tx.send(result);
});
}
}
}
pub struct MeasureCx {
pub constraint: Constraint,
}
pub struct LayoutCx<'a> {
children: &'a mut Vec<Node>,
}
impl<'a> LayoutCx<'a> {
pub(crate) fn new(children: &'a mut Vec<Node>) -> Self {
Self { children }
}
pub fn child_count(&self) -> usize {
self.children.len()
}
pub fn child_style(&self, index: usize) -> Option<Style> {
self.children.get(index).map(|n| n.component.style())
}
pub fn layout_child(&mut self, index: usize, rect: Rect) {
if let Some(child) = self.children.get_mut(index) {
child.layout(rect);
}
}
pub fn for_each_child(&mut self, mut f: impl FnMut(usize, &mut Node)) {
for (i, child) in self.children.iter_mut().enumerate() {
f(i, child);
}
}
}