use alloc::{boxed::Box, vec::Vec};
use core::fmt::Debug;
use ratatui_core::{buffer::Buffer, layout::Rect};
use crate::{
cell_filter::FilterProcessor, cell_iter::CellIterator, pattern::AnyPattern, widget::EffectSpan,
CellFilter, ColorSpace, Duration, EffectTimer, SimpleRng, ThreadSafetyMarker,
};
pub trait Shader: ThreadSafetyMarker + Debug {
fn name(&self) -> &'static str;
fn process(&mut self, duration: Duration, buf: &mut Buffer, area: Rect) -> Option<Duration> {
let overflow = self.timer_mut().and_then(|t| t.process(duration));
self.execute(duration, area, buf);
overflow
}
#[allow(unused_variables)]
fn execute(&mut self, duration: Duration, area: Rect, buf: &mut Buffer) {}
fn cell_iter<'a>(&'a mut self, buf: &'a mut Buffer, area: Rect) -> CellIterator<'a> {
CellIterator::new(buf, area, self.filter_processor())
}
fn done(&self) -> bool;
fn running(&self) -> bool {
!self.done()
}
fn clone_box(&self) -> Box<dyn Shader>;
fn area(&self) -> Option<Rect>;
fn set_area(&mut self, area: Rect);
fn filter(&mut self, filter: CellFilter);
#[deprecated(since = "0.11.0", note = "Use `filter()` instead")]
fn set_cell_selection(&mut self, filter: CellFilter) {
self.filter(filter);
}
fn reverse(&mut self) {
if let Some(timer) = self.timer_mut() {
*timer = timer.reversed();
}
}
fn timer_mut(&mut self) -> Option<&mut EffectTimer> {
None
}
fn timer(&self) -> Option<EffectTimer> {
None
}
fn cell_filter(&self) -> Option<&CellFilter> {
None
}
fn filter_processor(&self) -> Option<&FilterProcessor> {
None
}
fn filter_processor_mut(&mut self) -> Option<&mut FilterProcessor> {
None
}
#[deprecated(since = "0.11.0", note = "Use `cell_filter()` instead")]
fn cell_selection(&self) -> Option<CellFilter> {
self.cell_filter().cloned()
}
#[allow(unused_variables)]
fn set_color_space(&mut self, color_space: ColorSpace) {}
fn color_space(&self) -> ColorSpace {
ColorSpace::default()
}
#[allow(unused_variables)]
fn set_pattern(&mut self, pattern: AnyPattern) {
}
#[allow(unused_variables)]
fn set_rng(&mut self, rng: SimpleRng) {}
fn reset(&mut self) {
if let Some(timer) = self.timer_mut() {
timer.reset();
} else {
panic!("Shader must implement reset()")
}
}
#[cfg(feature = "dsl")]
fn to_dsl(&self) -> Result<crate::dsl::EffectExpression, crate::dsl::DslError> {
use crate::dsl::DslError;
Err(DslError::EffectExpressionNotSupported { name: self.name() })
}
#[deprecated(since = "0.23.0", note = "EffectSpan is being removed")]
fn as_effect_span(&self, offset: Duration) -> EffectSpan {
EffectSpan::new(self, offset, Vec::default())
}
}
#[macro_export]
macro_rules! default_shader_impl {
( $($group:ident),* ) => {
$(
default_shader_impl!(@$group);
)*
};
(@area) => {
fn area(&self) -> Option<Rect> {
self.area
}
fn set_area(&mut self, area: Rect) {
self.area = Some(area);
}
};
(@timer) => {
fn done(&self) -> bool {
self.timer.done()
}
fn timer_mut(&mut self) -> Option<&mut EffectTimer> {
Some(&mut self.timer)
}
fn timer(&self) -> Option<EffectTimer> {
Some(self.timer)
}
};
(@filter) => {
fn filter(&mut self, strategy: CellFilter) {
self.cell_filter = Some(FilterProcessor::from(strategy));
}
fn cell_filter(&self) -> Option<&CellFilter> {
self.cell_filter.as_ref().map(|f| f.filter_ref())
}
fn filter_processor(&self) -> Option<&FilterProcessor> {
self.cell_filter.as_ref()
}
fn filter_processor_mut(&mut self) -> Option<&mut FilterProcessor> {
self.cell_filter.as_mut()
}
};
(@color_space) => {
fn set_color_space(&mut self, color_space: ColorSpace) {
self.color_space = color_space;
}
fn color_space(&self) -> ColorSpace {
self.color_space
}
};
(@clone) => {
fn clone_box(&self) -> Box<dyn Shader> {
Box::new(self.clone())
}
};
}