mirror of
https://github.com/mfontanini/presenterm.git
synced 2025-05-05 15:32:58 +00:00
feat: add collapse_horizontal
slide transition (#560)
This adds a new `collapse_horizontal` slide transition that collapses the current slide into the center of the screen. https://github.com/user-attachments/assets/a398c286-ae3e-4c99-81aa-26aba498726d
This commit is contained in:
commit
94ce0a9225
@ -586,6 +586,22 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"description": "Collapse the current slide into the center of the screen.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"style"
|
||||
],
|
||||
"properties": {
|
||||
"style": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"collapse_horizontal"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -553,6 +553,9 @@ pub enum SlideTransitionStyleConfig {
|
||||
|
||||
/// Fade the new slide into the previous one.
|
||||
Fade,
|
||||
|
||||
/// Collapse the current slide into the center of the screen.
|
||||
CollapseHorizontal,
|
||||
}
|
||||
|
||||
fn make_keybindings<const N: usize>(raw_bindings: [&str; N]) -> Vec<KeyBinding> {
|
||||
|
@ -29,7 +29,8 @@ use crate::{
|
||||
theme::{ProcessingThemeError, raw::PresentationTheme},
|
||||
third_party::ThirdPartyRender,
|
||||
transitions::{
|
||||
AnimateTransition, AnimationFrame, LinesFrame, TransitionDirection, fade::FadeAnimation,
|
||||
AnimateTransition, AnimationFrame, LinesFrame, TransitionDirection,
|
||||
collapse_horizontal::CollapseHorizontalAnimation, fade::FadeAnimation,
|
||||
slide_horizontal::SlideHorizontalAnimation,
|
||||
},
|
||||
};
|
||||
@ -518,6 +519,9 @@ impl<'a> Presenter<'a> {
|
||||
SlideTransitionStyleConfig::Fade => {
|
||||
self.run_animation(drawer, first, FadeAnimation::new(left, right, direction), config)
|
||||
}
|
||||
SlideTransitionStyleConfig::CollapseHorizontal => {
|
||||
self.run_animation(drawer, first, CollapseHorizontalAnimation::new(left, right, direction), config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
65
src/transitions/collapse_horizontal.rs
Normal file
65
src/transitions/collapse_horizontal.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use super::{AnimateTransition, LinesFrame, TransitionDirection};
|
||||
use crate::terminal::virt::TerminalGrid;
|
||||
|
||||
pub(crate) struct CollapseHorizontalAnimation {
|
||||
from: TerminalGrid,
|
||||
to: TerminalGrid,
|
||||
}
|
||||
|
||||
impl CollapseHorizontalAnimation {
|
||||
pub(crate) fn new(left: TerminalGrid, right: TerminalGrid, direction: TransitionDirection) -> Self {
|
||||
let (from, to) = match direction {
|
||||
TransitionDirection::Next => (left, right),
|
||||
TransitionDirection::Previous => (right, left),
|
||||
};
|
||||
Self { from, to }
|
||||
}
|
||||
}
|
||||
|
||||
impl AnimateTransition for CollapseHorizontalAnimation {
|
||||
type Frame = LinesFrame;
|
||||
|
||||
fn build_frame(&self, frame: usize, _previous_frame: usize) -> Self::Frame {
|
||||
let mut rows = Vec::new();
|
||||
for (from, to) in self.from.rows.iter().zip(&self.to.rows) {
|
||||
// Take the first and last `frame` cells
|
||||
let to_prefix = to.iter().take(frame);
|
||||
let to_suffix = to.iter().rev().take(frame).rev();
|
||||
|
||||
let total_rows_from = from.len() - frame * 2;
|
||||
let from = from.iter().skip(frame).take(total_rows_from);
|
||||
let row = to_prefix.chain(from).chain(to_suffix).copied().collect();
|
||||
rows.push(row)
|
||||
}
|
||||
let grid = TerminalGrid { rows, background_color: self.from.background_color, images: Default::default() };
|
||||
LinesFrame::from(&grid)
|
||||
}
|
||||
|
||||
fn total_frames(&self) -> usize {
|
||||
self.from.rows[0].len() / 2
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{markdown::elements::Line, transitions::utils::build_grid};
|
||||
use rstest::rstest;
|
||||
|
||||
fn as_text(line: Line) -> String {
|
||||
line.0.into_iter().map(|l| l.content).collect()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(0, &["ABCDEF"])]
|
||||
#[case(1, &["1BCDE6"])]
|
||||
#[case(2, &["12CD56"])]
|
||||
#[case(3, &["123456"])]
|
||||
fn transition(#[case] frame: usize, #[case] expected: &[&str]) {
|
||||
let left = build_grid(&["ABCDEF"]);
|
||||
let right = build_grid(&["123456"]);
|
||||
let transition = CollapseHorizontalAnimation::new(left, right, TransitionDirection::Next);
|
||||
let lines: Vec<_> = transition.build_frame(frame, 0).lines.into_iter().map(as_text).collect();
|
||||
assert_eq!(lines, expected);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ use crate::{
|
||||
use std::fmt::Debug;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
pub(crate) mod collapse_horizontal;
|
||||
pub(crate) mod fade;
|
||||
pub(crate) mod slide_horizontal;
|
||||
|
||||
@ -109,6 +110,19 @@ impl AnimationFrame for LinesFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod utils {
|
||||
use crate::terminal::virt::{StyledChar, TerminalGrid};
|
||||
|
||||
pub(crate) fn build_grid(rows: &[&str]) -> TerminalGrid {
|
||||
let rows = rows
|
||||
.iter()
|
||||
.map(|r| r.chars().map(|c| StyledChar { character: c, style: Default::default() }).collect())
|
||||
.collect();
|
||||
TerminalGrid { rows, background_color: None, images: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -69,21 +69,12 @@ impl AnimateTransition for SlideHorizontalAnimation {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::terminal::virt::StyledChar;
|
||||
use rstest::rstest;
|
||||
|
||||
fn as_text(line: Line) -> String {
|
||||
line.0.into_iter().map(|l| l.content).collect()
|
||||
}
|
||||
|
||||
fn build_grid(rows: &[&str]) -> TerminalGrid {
|
||||
let rows = rows
|
||||
.iter()
|
||||
.map(|r| r.chars().map(|c| StyledChar { character: c, style: Default::default() }).collect())
|
||||
.collect();
|
||||
TerminalGrid { rows, background_color: None, images: Default::default() }
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::next_frame0(0, TransitionDirection::Next, &["AB", "CD"])]
|
||||
#[case::next_frame1(1, TransitionDirection::Next, &["BE", "DG"])]
|
||||
@ -94,6 +85,8 @@ mod tests {
|
||||
#[case::previous_frame2(2, TransitionDirection::Previous, &["AB", "CD"])]
|
||||
#[case::previous_way_past(100, TransitionDirection::Previous, &["AB", "CD"])]
|
||||
fn build_frame(#[case] frame: usize, #[case] direction: TransitionDirection, #[case] expected: &[&str]) {
|
||||
use crate::transitions::utils::build_grid;
|
||||
|
||||
let left = build_grid(&["AB", "CD"]);
|
||||
let right = build_grid(&["EF", "GH"]);
|
||||
let dimensions = WindowSize { rows: 2, columns: 2, height: 0, width: 0 };
|
||||
|
Loading…
x
Reference in New Issue
Block a user