mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-12-22 22:26:41 +00:00
Add comments
This commit is contained in:
parent
e07d5bfb3e
commit
4286d7055d
@ -1,20 +1,27 @@
|
||||
/// A sample for a terminal cell.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum CharSample {
|
||||
/// Keep the char.
|
||||
Keep,
|
||||
/// Override the char.
|
||||
Draw(char),
|
||||
/// Clear the char.
|
||||
Clear,
|
||||
}
|
||||
|
||||
/// A trait to convert a sample to a [CharSample].
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait CharConverter {
|
||||
fn convert(&self, level: f32) -> CharSample;
|
||||
}
|
||||
|
||||
/// The implementation of [CharConverter].
|
||||
pub struct CharConverterImpl {
|
||||
chars: Vec<char>,
|
||||
}
|
||||
|
||||
impl CharConverterImpl {
|
||||
/// The chars used for mapping.
|
||||
pub fn new(chars: String) -> Self {
|
||||
let chars = chars.chars().collect();
|
||||
|
||||
|
@ -1,15 +1,18 @@
|
||||
use crossterm::style::Color;
|
||||
|
||||
/// A trait to convert a sample to a [Color].
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait ColorConverter {
|
||||
fn convert(&self, level: f32) -> Color;
|
||||
}
|
||||
|
||||
/// The implementation of [ColorConverter].
|
||||
pub struct ColorConverterImpl {
|
||||
colors: Vec<Color>,
|
||||
}
|
||||
|
||||
impl ColorConverterImpl {
|
||||
/// The colors used for mapping.
|
||||
pub fn new(colors: Vec<Color>) -> Self {
|
||||
Self { colors }
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Contains structs for converting samples to concrete types.
|
||||
|
||||
mod char;
|
||||
mod color;
|
||||
|
||||
@ -6,12 +8,16 @@ pub use crate::convert::color::*;
|
||||
|
||||
use crossterm::style::Color;
|
||||
|
||||
/// A trait to convert samples to concrete types.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Converter {
|
||||
/// Converts a sample to a [CharSample].
|
||||
fn char(&self, level: f32) -> CharSample;
|
||||
/// Converts a sample to a [Color].
|
||||
fn color(&self, level: f32) -> Color;
|
||||
}
|
||||
|
||||
/// The implementation of [Converter].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct ConverterImpl<T1, T2> {
|
||||
char: T1,
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
/// The error type.
|
||||
pub struct Error(String);
|
||||
|
||||
impl Debug for Error {
|
||||
|
21
src/main.rs
21
src/main.rs
@ -27,6 +27,7 @@ use rand::prelude::*;
|
||||
use std::io::stdout;
|
||||
use std::time::Duration;
|
||||
|
||||
/// The command line arguments.
|
||||
#[derive(Parser, Default)]
|
||||
#[clap(
|
||||
author = env!("CARGO_PKG_AUTHORS"),
|
||||
@ -34,8 +35,13 @@ use std::time::Duration;
|
||||
about = env!("CARGO_PKG_DESCRIPTION"),
|
||||
)]
|
||||
struct Args {
|
||||
/// Set the animation duration [milliseconds]
|
||||
#[clap(long, default_value_t = 2000, value_parser = value_parser!(u64).range(0..=60_000))]
|
||||
/// Set the duration as milliseconds
|
||||
#[clap(
|
||||
long,
|
||||
default_value_t = 2000,
|
||||
value_parser = value_parser!(u64).range(0..=60_000),
|
||||
help = "Set the animation duration [milliseconds]"
|
||||
)]
|
||||
duration: u64,
|
||||
/// Set the frames per second
|
||||
#[clap(long, default_value_t = 60, value_parser = value_parser!(u64).range(1..=480))]
|
||||
@ -78,6 +84,7 @@ struct Args {
|
||||
color_slices: Option<u8>,
|
||||
}
|
||||
|
||||
/// All color pallets.
|
||||
#[derive(ValueEnum, Copy, Clone)]
|
||||
enum PalletEnum {
|
||||
Red,
|
||||
@ -106,6 +113,7 @@ enum PalletEnum {
|
||||
Gray,
|
||||
}
|
||||
|
||||
/// All possible [Pattern]s.
|
||||
#[derive(ValueEnum, Copy, Clone, PartialEq, Debug)]
|
||||
enum PatternEnum {
|
||||
Circle,
|
||||
@ -114,6 +122,7 @@ enum PatternEnum {
|
||||
Wheel,
|
||||
}
|
||||
|
||||
/// A configuration for a composed [Pattern].
|
||||
#[derive(derive_more::Constructor)]
|
||||
struct PatternConfig {
|
||||
pattern: PatternEnum,
|
||||
@ -125,6 +134,7 @@ struct PatternConfig {
|
||||
}
|
||||
|
||||
impl Args {
|
||||
/// Returns the configuration for the char [Pattern].
|
||||
fn char_config(&self, rng: &mut impl Rng) -> PatternConfig {
|
||||
PatternConfig::new(
|
||||
choose(self.char_pattern, rng),
|
||||
@ -136,6 +146,7 @@ impl Args {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the configuration for the color [Pattern].
|
||||
fn color_config(&self, rng: &mut impl Rng) -> PatternConfig {
|
||||
PatternConfig::new(
|
||||
choose(self.color_pattern, rng),
|
||||
@ -147,6 +158,7 @@ impl Args {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the colors for the [ColorConverter].
|
||||
fn pallet(&self, rng: &mut impl Rng) -> Vec<Color> {
|
||||
match choose(self.colors, rng) {
|
||||
PalletEnum::Red => vec![DarkRed, Red, White],
|
||||
@ -183,16 +195,19 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the duration for the [Timer].
|
||||
fn duration(&self) -> Duration {
|
||||
Duration::from_millis(self.duration)
|
||||
}
|
||||
|
||||
/// Returns the delay for the [Timer].
|
||||
fn delay(&self) -> Duration {
|
||||
Duration::from_nanos(1_000_000_000 / self.fps)
|
||||
}
|
||||
}
|
||||
|
||||
impl PatternConfig {
|
||||
/// Creates a new base [Pattern].
|
||||
fn create_base(&self) -> Box<dyn PatternFactory> {
|
||||
match self.pattern {
|
||||
PatternEnum::Circle => Box::new(CircleFactory::new()),
|
||||
@ -202,6 +217,7 @@ impl PatternConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new composed [Pattern].
|
||||
fn create(&self) -> Box<dyn PatternFactory> {
|
||||
let mut pattern = self.create_base();
|
||||
|
||||
@ -224,6 +240,7 @@ impl PatternConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value of the [Option] or a random enum variant.
|
||||
fn choose<TValue: ValueEnum, TRand: Rng>(opt: Option<TValue>, rng: &mut TRand) -> TValue {
|
||||
match opt {
|
||||
Some(value) => value.clone(),
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Circle].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct CircleFactory;
|
||||
/// A circular [Pattern].
|
||||
pub struct Circle {
|
||||
center: Vector,
|
||||
radius: f32,
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Line].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct LineFactory;
|
||||
/// A horizontal line [Pattern].
|
||||
pub struct Line {
|
||||
width: f32,
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Contains all pattern traits and base patterns.
|
||||
|
||||
mod circle;
|
||||
mod line;
|
||||
mod rhombus;
|
||||
@ -10,42 +12,59 @@ pub use wheel::*;
|
||||
|
||||
use crate::Vector;
|
||||
|
||||
/// A configuration for a [Pattern].
|
||||
#[derive(Copy, Clone, Default, PartialEq, Debug)]
|
||||
pub struct Config {
|
||||
/// The size of the terminal.
|
||||
pub size: Vector,
|
||||
/// The current state of the animation.
|
||||
pub step: f32,
|
||||
}
|
||||
|
||||
/// A factory to create a [Pattern].
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait PatternFactory {
|
||||
/// Creates a new [Pattern] with the given configuration.
|
||||
fn create(&self, config: &Config) -> Box<dyn Pattern>;
|
||||
}
|
||||
|
||||
/// A pattern for an animation.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Pattern {
|
||||
/// Returns the level for a given coordinate.
|
||||
/// If it is a base pattern, the start position of the
|
||||
/// animation should by zero and the end position should be one.
|
||||
fn sample(&self, pos: Vector) -> f32;
|
||||
}
|
||||
|
||||
/// A factor for a [Sampler].
|
||||
#[cfg_attr(test, mockall::automock(type Sampler = MockSampler;))]
|
||||
pub trait SamplerFactory {
|
||||
/// The type of the [Sampler].
|
||||
type Sampler: Sampler;
|
||||
|
||||
/// Creates a new [Sampler].
|
||||
fn create(&self, config: &Config) -> Self::Sampler;
|
||||
}
|
||||
|
||||
/// A sampler for multiple values.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Sampler {
|
||||
/// Returns the char level for a given position.
|
||||
fn char(&self, pos: Vector) -> f32;
|
||||
|
||||
/// Returns the color level for a given position.
|
||||
fn color(&self, pos: Vector) -> f32;
|
||||
}
|
||||
|
||||
/// The implementation of [SamplerFactory].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct SamplerFactoryImpl {
|
||||
char: Box<dyn PatternFactory>,
|
||||
color: Box<dyn PatternFactory>,
|
||||
}
|
||||
|
||||
/// The implementation of [Sampler].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct SamplerImpl {
|
||||
char: Box<dyn Pattern>,
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Rhombus].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct RhombusFactory;
|
||||
/// A rhombus shaped [Pattern].
|
||||
pub struct Rhombus {
|
||||
center: Vector,
|
||||
distance: f32,
|
||||
|
@ -2,8 +2,10 @@ use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
/// A factory for [Wheel].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct WheelFactory;
|
||||
/// A fortune wheel [Pattern].
|
||||
pub struct Wheel {
|
||||
center: Vector,
|
||||
}
|
||||
|
@ -4,18 +4,32 @@ use crossterm::cursor::*;
|
||||
use crossterm::style::*;
|
||||
use crossterm::terminal::*;
|
||||
|
||||
/// A trait for performance optimized terminal output.
|
||||
///
|
||||
/// All commands are queue and have to be executed using [Printer::flush].
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Printer {
|
||||
/// Shows the cursor if it isn't visible.
|
||||
fn show_cursor(&mut self) -> Result<(), Error>;
|
||||
/// Hides the cursor if it is visible.
|
||||
fn hide_cursor(&mut self) -> Result<(), Error>;
|
||||
/// Prints a character.
|
||||
/// # Panics
|
||||
/// Panics if the character is a special character like `ESC`, `DEL` or `NEWLINE`.
|
||||
fn print(&mut self, char: char) -> Result<(), Error>;
|
||||
/// Moves the cursor to the specified position if it isn't there already.
|
||||
fn move_to(&mut self, x: u16, y: u16) -> Result<(), Error>;
|
||||
/// Returns the size of the terminal.
|
||||
fn size(&self) -> Result<(u16, u16), Error>;
|
||||
/// Sets the foreground color of the terminal.
|
||||
fn set_foreground(&mut self, color: Color) -> Result<(), Error>;
|
||||
/// Clears the terminal content.
|
||||
fn clear(&mut self) -> Result<(), Error>;
|
||||
/// Flushes all queue commands.
|
||||
fn flush(&mut self) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// The implementation of [Printer].
|
||||
pub struct PrinterImpl<T> {
|
||||
term: T,
|
||||
position: (u16, u16),
|
||||
|
@ -4,13 +4,20 @@ use crate::Error;
|
||||
use crate::Printer;
|
||||
use crate::Vector;
|
||||
|
||||
/// A renderer for an animation.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Renderer {
|
||||
/// Prepares the terminal for the animation.
|
||||
/// Call once before rendering frames.
|
||||
fn begin(&mut self) -> Result<(), Error>;
|
||||
/// Renders the current frame and flushes.
|
||||
fn render(&mut self, step: f32) -> Result<(), Error>;
|
||||
/// Cleans up and resets the terminal.
|
||||
/// Call once after rendering frames.
|
||||
fn end(&mut self) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// The implementation of [Renderer].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct RendererImpl<T1, T2, T3> {
|
||||
sampler: T1,
|
||||
|
@ -2,14 +2,20 @@ use crate::Error;
|
||||
use crossterm::{Command, QueueableCommand};
|
||||
use std::io::Write;
|
||||
|
||||
/// A stub for OS calls and crossterm functions.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Terminal {
|
||||
/// Queues a command for execution.
|
||||
fn queue<T: 'static + Command>(&mut self, cmd: T) -> Result<(), Error>;
|
||||
/// Flushes all queued commands.
|
||||
fn flush(&mut self) -> Result<(), Error>;
|
||||
/// Returns the current size of the terminal.
|
||||
fn size(&self) -> Result<(u16, u16), Error>;
|
||||
/// Returns the current cursor position.
|
||||
fn position(&self) -> Result<(u16, u16), Error>;
|
||||
}
|
||||
|
||||
/// The implementation of [Terminal].
|
||||
pub struct TerminalImpl<T> {
|
||||
out: T,
|
||||
}
|
||||
|
@ -3,12 +3,17 @@ use crate::Renderer;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// A stub for the system clock.
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait Clock {
|
||||
/// Returns the current time.
|
||||
fn now(&self) -> Instant;
|
||||
|
||||
/// Sleep for the given duration.
|
||||
fn sleep(&self, duration: Duration);
|
||||
}
|
||||
|
||||
/// The implementation of [Clock].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct ClockImpl;
|
||||
|
||||
@ -22,6 +27,7 @@ impl Clock for ClockImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/// A timer for rendering.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Timer<T> {
|
||||
clock: T,
|
||||
@ -30,6 +36,7 @@ pub struct Timer<T> {
|
||||
}
|
||||
|
||||
impl<T: Clock> Timer<T> {
|
||||
/// Runs the animation main loop.
|
||||
pub fn run(&self, mut renderer: impl Renderer) -> Result<(), Error> {
|
||||
let start = self.clock.now();
|
||||
let mut now = start;
|
||||
@ -45,6 +52,8 @@ impl<T: Clock> Timer<T> {
|
||||
renderer.end()
|
||||
}
|
||||
|
||||
/// Sleeps until the next frame starts.
|
||||
/// Returns the current time.
|
||||
fn delay(&self, begin: Instant) -> Instant {
|
||||
let end = self.clock.now();
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Invert].
|
||||
///
|
||||
/// Inverts the time of the [Config] for the child [Pattern].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct InvertFactory {
|
||||
child: Box<dyn PatternFactory>,
|
||||
}
|
||||
|
||||
/// Inverts the level of the [Pattern].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Invert {
|
||||
child: Box<dyn Pattern>,
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Contains transformations to apply on top of patterns.
|
||||
|
||||
mod invert;
|
||||
mod segment;
|
||||
mod shift;
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Segments].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct SegmentsFactory {
|
||||
child: Box<dyn PatternFactory>,
|
||||
segments: f32,
|
||||
}
|
||||
|
||||
/// Converts a pattern to `n` segments each starting with zero and ending with one.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Segments {
|
||||
child: Box<dyn Pattern>,
|
||||
|
@ -1,11 +1,13 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Shift].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct ShiftFactory {
|
||||
child: Box<dyn PatternFactory>,
|
||||
}
|
||||
|
||||
/// Offsets the [Pattern] out of screen, then moves it inside and finally outside the visible area.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Shift {
|
||||
child: Box<dyn Pattern>,
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Slice].
|
||||
pub struct SliceFactory {
|
||||
child: Box<dyn PatternFactory>,
|
||||
width: f32,
|
||||
rest: f32,
|
||||
}
|
||||
|
||||
/// Reduces the width of the child [Pattern] to one over `n`.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Slice {
|
||||
child: Box<dyn Pattern>,
|
||||
|
@ -1,11 +1,15 @@
|
||||
use crate::pattern::*;
|
||||
use crate::Vector;
|
||||
|
||||
/// A factory for [Swap].
|
||||
///
|
||||
/// Swaps the x-axis and y-axis of terminal size for the contained [Pattern].
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct SwapFactory {
|
||||
child: Box<dyn PatternFactory>,
|
||||
}
|
||||
|
||||
/// Swaps the x-axis and y-axis.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Swap {
|
||||
child: Box<dyn Pattern>,
|
||||
|
@ -1,3 +1,4 @@
|
||||
/// A vector with a x-axis and y-axis.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Default, derive_more::Sub)]
|
||||
pub struct Vector {
|
||||
pub x: f32,
|
||||
@ -5,34 +6,42 @@ pub struct Vector {
|
||||
}
|
||||
|
||||
impl Vector {
|
||||
/// Creates a new vector.
|
||||
pub fn new(x: f32, y: f32) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
/// Creates a new vector from terminal coordinates.
|
||||
pub fn from_terminal(x: u16, y: u16) -> Self {
|
||||
Vector::new(x as f32, y as f32 * 2.0)
|
||||
}
|
||||
|
||||
/// Returns the length.
|
||||
pub fn len(&self) -> f32 {
|
||||
(self.x * self.x + self.y * self.y).sqrt()
|
||||
}
|
||||
|
||||
/// Returns a vector with absolute values.
|
||||
pub fn abs(&self) -> Vector {
|
||||
Self::new(self.x.abs(), self.y.abs())
|
||||
}
|
||||
|
||||
/// Returns the sum of all axis.
|
||||
pub fn sum(&self) -> f32 {
|
||||
self.x + self.y
|
||||
}
|
||||
|
||||
/// Returns the center.
|
||||
pub fn center(&self) -> Vector {
|
||||
Self::new(self.x / 2.0, self.y / 2.0)
|
||||
}
|
||||
|
||||
/// Returns the angle.
|
||||
pub fn angle(&self) -> f32 {
|
||||
self.y.atan2(self.x)
|
||||
}
|
||||
|
||||
/// Returns a vector with x and y swapped.
|
||||
pub fn swap(&self) -> Vector {
|
||||
Self::new(self.y, self.x)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user