use ffmpeg_common::CommandBuilder;
use crate::types::ShowMode;
#[derive(Debug, Clone, Default)]
pub struct DisplayOptions {
width: Option<u32>,
height: Option<u32>,
fullscreen: bool,
no_display: bool,
borderless: bool,
always_on_top: bool,
window_title: Option<String>,
left: Option<i32>,
top: Option<i32>,
show_mode: Option<ShowMode>,
}
impl DisplayOptions {
pub fn new() -> Self {
Self::default()
}
pub fn width(mut self, width: u32) -> Self {
self.width = Some(width);
self
}
pub fn height(mut self, height: u32) -> Self {
self.height = Some(height);
self
}
pub fn size(mut self, width: u32, height: u32) -> Self {
self.width = Some(width);
self.height = Some(height);
self
}
pub fn fullscreen(mut self, enable: bool) -> Self {
self.fullscreen = enable;
self
}
pub fn no_display(mut self, enable: bool) -> Self {
self.no_display = enable;
self
}
pub fn borderless(mut self, enable: bool) -> Self {
self.borderless = enable;
self
}
pub fn always_on_top(mut self, enable: bool) -> Self {
self.always_on_top = enable;
self
}
pub fn window_title(mut self, title: impl Into<String>) -> Self {
self.window_title = Some(title.into());
self
}
pub fn position(mut self, x: i32, y: i32) -> Self {
self.left = Some(x);
self.top = Some(y);
self
}
pub fn left(mut self, x: i32) -> Self {
self.left = Some(x);
self
}
pub fn top(mut self, y: i32) -> Self {
self.top = Some(y);
self
}
pub fn show_mode(mut self, mode: ShowMode) -> Self {
self.show_mode = Some(mode);
self
}
pub fn build_args(&self) -> Vec<String> {
let mut cmd = CommandBuilder::new();
if let Some(width) = self.width {
cmd = cmd.option("-x", width);
}
if let Some(height) = self.height {
cmd = cmd.option("-y", height);
}
if self.fullscreen {
cmd = cmd.flag("-fs");
}
if self.no_display {
cmd = cmd.flag("-nodisp");
}
if self.borderless {
cmd = cmd.flag("-noborder");
}
if self.always_on_top {
cmd = cmd.flag("-alwaysontop");
}
if let Some(ref title) = self.window_title {
cmd = cmd.option("-window_title", title);
}
if let Some(x) = self.left {
cmd = cmd.option("-left", x);
}
if let Some(y) = self.top {
cmd = cmd.option("-top", y);
}
if let Some(mode) = self.show_mode {
cmd = cmd.option("-showmode", mode as u8);
}
cmd.build()
}
}
pub mod presets {
use super::*;
pub fn standard() -> DisplayOptions {
DisplayOptions::new().size(1280, 720)
}
pub fn fullscreen() -> DisplayOptions {
DisplayOptions::new().fullscreen(true)
}
pub fn pip() -> DisplayOptions {
DisplayOptions::new()
.size(480, 270)
.borderless(true)
.always_on_top(true)
}
pub fn minimal() -> DisplayOptions {
DisplayOptions::new()
.borderless(true)
}
pub fn audio_viz() -> DisplayOptions {
DisplayOptions::new()
.size(800, 200)
.show_mode(ShowMode::Waves)
}
pub fn spectrum() -> DisplayOptions {
DisplayOptions::new()
.size(800, 400)
.show_mode(ShowMode::Rdft)
}
pub fn hidden() -> DisplayOptions {
DisplayOptions::new().no_display(true)
}
pub fn centered(width: u32, height: u32) -> DisplayOptions {
DisplayOptions::new().size(width, height)
}
pub fn top_left(width: u32, height: u32) -> DisplayOptions {
DisplayOptions::new()
.size(width, height)
.position(0, 0)
}
pub fn top_right(width: u32, height: u32, screen_width: u32) -> DisplayOptions {
DisplayOptions::new()
.size(width, height)
.position((screen_width - width) as i32, 0)
}
pub fn bottom_left(width: u32, height: u32, screen_height: u32) -> DisplayOptions {
DisplayOptions::new()
.size(width, height)
.position(0, (screen_height - height) as i32)
}
pub fn bottom_right(
width: u32,
height: u32,
screen_width: u32,
screen_height: u32,
) -> DisplayOptions {
DisplayOptions::new()
.size(width, height)
.position(
(screen_width - width) as i32,
(screen_height - height) as i32,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_options() {
let opts = DisplayOptions::new()
.size(1920, 1080)
.fullscreen(true)
.window_title("Test Video");
let args = opts.build_args();
assert!(args.contains(&"-x".to_string()));
assert!(args.contains(&"1920".to_string()));
assert!(args.contains(&"-y".to_string()));
assert!(args.contains(&"1080".to_string()));
assert!(args.contains(&"-fs".to_string()));
assert!(args.contains(&"-window_title".to_string()));
assert!(args.contains(&"Test Video".to_string()));
}
#[test]
fn test_position() {
let opts = DisplayOptions::new()
.position(100, 200);
let args = opts.build_args();
assert!(args.contains(&"-left".to_string()));
assert!(args.contains(&"100".to_string()));
assert!(args.contains(&"-top".to_string()));
assert!(args.contains(&"200".to_string()));
}
#[test]
fn test_show_mode() {
let opts = DisplayOptions::new()
.show_mode(ShowMode::Waves);
let args = opts.build_args();
assert!(args.contains(&"-showmode".to_string()));
assert!(args.contains(&"1".to_string()));
}
#[test]
fn test_presets() {
let standard = presets::standard();
let args = standard.build_args();
assert!(args.contains(&"1280".to_string()));
assert!(args.contains(&"720".to_string()));
let pip = presets::pip();
let args = pip.build_args();
assert!(args.contains(&"480".to_string()));
assert!(args.contains(&"270".to_string()));
assert!(args.contains(&"-noborder".to_string()));
assert!(args.contains(&"-alwaysontop".to_string()));
let hidden = presets::hidden();
let args = hidden.build_args();
assert!(args.contains(&"-nodisp".to_string()));
}
}