1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
use std::time::Duration;
use ratatui::buffer::{Buffer};
use ratatui::layout::{Rect};
use crate::cell_iter::CellIterator;
use crate::effect::CellFilter;
use crate::EffectTimer;
/// A trait representing a shader-like object that can be processed for a duration.
/// The `Shader` trait defines the interface for objects that can apply visual effects
/// to terminal cells over time.
pub trait Shader {
/// Processes the shader for the given duration. Returns any overflowed
/// duration if the shader has completed.
///
/// This default implementation calls `execute` with the alpha value and the cells.
///
/// # Arguments
/// * `duration` - The duration to process the shader for.
/// * `buf` - A mutable reference to the `Buffer` where the shader will be applied.
/// * `area` - The rectangular area within the buffer where the shader will be applied.
///
/// # Returns
/// * An `Option` containing the overflow duration if the shader is done, or `None`
/// if it is still running.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use ratatui::buffer::Buffer;
/// use ratatui::layout::Rect;
///
/// let mut shader = MyShader::new();
/// let area = Rect::new(0, 0, 10, 10);
/// let mut buffer = Buffer::empty(area);
/// let overflow = shader.process(Duration::from_millis(100), &mut buffer, area);
/// ```
fn process(
&mut self,
duration: Duration,
buf: &mut Buffer,
area: Rect,
) -> Option<Duration> {
let (overflow, alpha) = self.timer_mut()
.map(|t| (t.process(duration), t.alpha()))
.unwrap_or((None, 1.0));
let requested_cells = self.cell_iter(buf, area);
self.execute(alpha, area, requested_cells);
overflow
}
/// Executes the shader with the given alpha value and cells. This is where
/// the actual shader logic should be implemented.
///
/// # Arguments
/// * `alpha` - The alpha value indicating the progress of the shader effect.
/// * `area` - The rectangular area within the buffer where the shader will be applied.
/// * `cell_iter` - An iterator over the cells in the specified area.
fn execute(
&mut self,
alpha: f32,
area: Rect,
cell_iter: CellIterator,
);
/// Creates an iterator over the cells in the specified area, filtered by the shader's cell filter.
///
/// # Arguments
/// * `buf` - A mutable reference to the `Buffer` where the shader will be applied.
/// * `area` - The rectangular area within the buffer where the shader will be applied.
///
/// # Returns
/// * A `CellIterator` over the cells in the specified area.
fn cell_iter<'a>(
&mut self,
buf: &'a mut Buffer,
area: Rect,
) -> CellIterator<'a> {
CellIterator::new(buf, area, self.cell_selection())
}
/// Returns true if the shader effect is done.
///
/// # Returns
/// * `true` if the shader effect is done, `false` otherwise.
fn done(&self) -> bool;
/// Returns true if the shader is still running.
///
/// # Returns
/// * `true` if the shader is running, `false` otherwise.
fn running(&self) -> bool { !self.done() }
/// Creates a boxed clone of the shader.
///
/// # Returns
/// * A boxed clone of the shader.
fn clone_box(&self) -> Box<dyn Shader>;
/// Returns the area where the shader effect is applied.
///
/// # Returns
/// * An `Option` containing the rectangular area if set, or `None` if not set.
fn area(&self) -> Option<Rect>;
/// Sets the area where the shader effect will be applied.
///
/// # Arguments
/// * `area` - The rectangular area to set.
fn set_area(&mut self, area: Rect);
/// Sets the cell selection strategy for the shader.
///
/// # Arguments
/// * `filter` - The cell selection strategy to set.
///
/// # Example
/// ```
/// use tachyonfx::CellFilter;
///
/// let mut shader = MyShader::new();
/// shader.cell_selection(CellFilter::Not(CellFilter::Text));
/// ```
fn set_cell_selection(&mut self, filter: CellFilter);
/// Reverses the shader effect.
fn reverse(&mut self) {
if let Some(timer) = self.timer_mut() {
*timer = timer.reversed()
}
}
/// Returns a mutable reference to the shader's timer, if any.
///
/// # Returns
/// * An `Option` containing a mutable reference to the shader's `EffectTimer`, or `None` if not applicable.
///
/// # Example
/// ```
/// let mut shader = MyShader::new();
/// if let Some(timer) = shader.timer_mut() {
/// timer.reset();
/// }
/// ```
fn timer_mut(&mut self) -> Option<&mut EffectTimer> { None }
/// Returns the cell selection strategy for the shader, if any.
///
/// # Returns
/// * An `Option` containing the shader's `CellFilter`, or `None` if not applicable.
fn cell_selection(&self) -> Option<CellFilter> { None }
}