This commit is contained in:
parent
6532666c56
commit
ad14135ddf
6 changed files with 177 additions and 78 deletions
|
@ -1,12 +1,13 @@
|
||||||
use crisp::types::{Keyword, Symbol, Value};
|
use crisp::types::{Keyword, Symbol, Value};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
|
use mupdf::{Document, Page};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow,
|
pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow,
|
||||||
Row, Sqlite, SqliteConnection, SqlitePool,
|
Row, Sqlite, SqliteConnection, SqlitePool,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, sync::Arc};
|
||||||
use tracing::error;
|
use tracing::{debug, error};
|
||||||
|
|
||||||
use crate::{Background, Slide, SlideBuilder, TextAlignment};
|
use crate::{Background, Slide, SlideBuilder, TextAlignment};
|
||||||
|
|
||||||
|
@ -27,9 +28,7 @@ pub enum PresKind {
|
||||||
Generic,
|
Generic,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
|
||||||
)]
|
|
||||||
pub struct Presentation {
|
pub struct Presentation {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -37,6 +36,17 @@ pub struct Presentation {
|
||||||
pub kind: PresKind,
|
pub kind: PresKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for Presentation {}
|
||||||
|
|
||||||
|
impl PartialEq for Presentation {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
&& self.title == other.title
|
||||||
|
&& self.path == other.path
|
||||||
|
&& self.kind == other.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Presentation> for Value {
|
impl From<&Presentation> for Value {
|
||||||
fn from(value: &Presentation) -> Self {
|
fn from(value: &Presentation) -> Self {
|
||||||
Self::List(vec![Self::Symbol(Symbol("presentation".into()))])
|
Self::List(vec![Self::Symbol(Symbol("presentation".into()))])
|
||||||
|
@ -117,22 +127,36 @@ impl ServiceTrait for Presentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_slides(&self) -> Result<Vec<Slide>> {
|
fn to_slides(&self) -> Result<Vec<Slide>> {
|
||||||
let slide = SlideBuilder::new()
|
debug!(?self);
|
||||||
.background(
|
let background = Background::try_from(self.path.clone())
|
||||||
Background::try_from(self.path.clone())
|
.into_diagnostic()?;
|
||||||
.into_diagnostic()?,
|
debug!(?background);
|
||||||
)
|
let doc = Document::open(background.path.as_path())
|
||||||
.text("")
|
.into_diagnostic()?;
|
||||||
.audio("")
|
debug!(?doc);
|
||||||
.font("")
|
let pages = doc.page_count().into_diagnostic()?;
|
||||||
.font_size(50)
|
debug!(?pages);
|
||||||
.text_alignment(TextAlignment::MiddleCenter)
|
let mut slides: Vec<Slide> = vec![];
|
||||||
.video_loop(false)
|
for page in 0..pages {
|
||||||
.video_start_time(0.0)
|
let slide = SlideBuilder::new()
|
||||||
.video_end_time(0.0)
|
.background(
|
||||||
.build()?;
|
Background::try_from(self.path.clone())
|
||||||
|
.into_diagnostic()?,
|
||||||
Ok(vec![slide])
|
)
|
||||||
|
.text("")
|
||||||
|
.audio("")
|
||||||
|
.font("")
|
||||||
|
.font_size(50)
|
||||||
|
.text_alignment(TextAlignment::MiddleCenter)
|
||||||
|
.video_loop(false)
|
||||||
|
.video_start_time(0.0)
|
||||||
|
.video_end_time(0.0)
|
||||||
|
.pdf_index(page as u32)
|
||||||
|
.build()?;
|
||||||
|
slides.push(slide);
|
||||||
|
}
|
||||||
|
debug!(?slides);
|
||||||
|
Ok(slides)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_clone(&self) -> Box<dyn ServiceTrait> {
|
fn box_clone(&self) -> Box<dyn ServiceTrait> {
|
||||||
|
|
|
@ -318,8 +318,8 @@ impl From<&Image> for ServiceItem {
|
||||||
|
|
||||||
impl From<&Presentation> for ServiceItem {
|
impl From<&Presentation> for ServiceItem {
|
||||||
fn from(presentation: &Presentation) -> Self {
|
fn from(presentation: &Presentation) -> Self {
|
||||||
if let Ok(slides) = presentation.to_slides() {
|
match presentation.to_slides() {
|
||||||
Self {
|
Ok(slides) => Self {
|
||||||
kind: ServiceItemKind::Presentation(
|
kind: ServiceItemKind::Presentation(
|
||||||
presentation.clone(),
|
presentation.clone(),
|
||||||
),
|
),
|
||||||
|
@ -327,15 +327,17 @@ impl From<&Presentation> for ServiceItem {
|
||||||
title: presentation.title.clone(),
|
title: presentation.title.clone(),
|
||||||
slides: slides.into(),
|
slides: slides.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
},
|
||||||
} else {
|
Err(e) => {
|
||||||
Self {
|
error!(?e);
|
||||||
kind: ServiceItemKind::Presentation(
|
Self {
|
||||||
presentation.clone(),
|
kind: ServiceItemKind::Presentation(
|
||||||
),
|
presentation.clone(),
|
||||||
database_id: presentation.id,
|
),
|
||||||
title: presentation.title.clone(),
|
database_id: presentation.id,
|
||||||
..Default::default()
|
title: presentation.title.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,10 @@ use std::{
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::ui::text_svg::{self, TextSvg};
|
use crate::ui::{
|
||||||
|
pdf::PdfViewer,
|
||||||
|
text_svg::{self, TextSvg},
|
||||||
|
};
|
||||||
|
|
||||||
use super::songs::Song;
|
use super::songs::Song;
|
||||||
|
|
||||||
|
@ -29,6 +32,7 @@ pub struct Slide {
|
||||||
video_loop: bool,
|
video_loop: bool,
|
||||||
video_start_time: f32,
|
video_start_time: f32,
|
||||||
video_end_time: f32,
|
video_end_time: f32,
|
||||||
|
pdf_index: u32,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub text_svg: Option<TextSvg>,
|
pub text_svg: Option<TextSvg>,
|
||||||
}
|
}
|
||||||
|
@ -40,6 +44,8 @@ pub enum BackgroundKind {
|
||||||
#[default]
|
#[default]
|
||||||
Image,
|
Image,
|
||||||
Video,
|
Video,
|
||||||
|
Pdf,
|
||||||
|
Html,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
@ -157,16 +163,22 @@ impl TryFrom<PathBuf> for Background {
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
match extension {
|
match extension {
|
||||||
"jpeg" | "jpg" | "png" | "webp" | "html" => {
|
"jpeg" | "jpg" | "png" | "webp" => Ok(Self {
|
||||||
Ok(Self {
|
path: value,
|
||||||
path: value,
|
kind: BackgroundKind::Image,
|
||||||
kind: BackgroundKind::Image,
|
}),
|
||||||
})
|
|
||||||
}
|
|
||||||
"mp4" | "mkv" | "webm" => Ok(Self {
|
"mp4" | "mkv" | "webm" => Ok(Self {
|
||||||
path: value,
|
path: value,
|
||||||
kind: BackgroundKind::Video,
|
kind: BackgroundKind::Video,
|
||||||
}),
|
}),
|
||||||
|
"pdf" => Ok(Self {
|
||||||
|
path: value,
|
||||||
|
kind: BackgroundKind::Pdf,
|
||||||
|
}),
|
||||||
|
"html" => Ok(Self {
|
||||||
|
path: value,
|
||||||
|
kind: BackgroundKind::Html,
|
||||||
|
}),
|
||||||
_ => Err(ParseError::NonBackgroundFile),
|
_ => Err(ParseError::NonBackgroundFile),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,6 +293,11 @@ impl Slide {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_pdf_index(mut self, pdf_index: u32) -> Self {
|
||||||
|
self.pdf_index = pdf_index;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn background(&self) -> &Background {
|
pub fn background(&self) -> &Background {
|
||||||
&self.background
|
&self.background
|
||||||
}
|
}
|
||||||
|
@ -309,6 +326,10 @@ impl Slide {
|
||||||
self.audio.clone()
|
self.audio.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pdf_index(&self) -> u32 {
|
||||||
|
self.pdf_index
|
||||||
|
}
|
||||||
|
|
||||||
pub fn song_slides(song: &Song) -> Result<Vec<Self>> {
|
pub fn song_slides(song: &Song) -> Result<Vec<Self>> {
|
||||||
let lyrics = song.get_lyrics()?;
|
let lyrics = song.get_lyrics()?;
|
||||||
let slides: Vec<Slide> = lyrics
|
let slides: Vec<Slide> = lyrics
|
||||||
|
@ -524,6 +545,7 @@ pub struct SlideBuilder {
|
||||||
video_loop: Option<bool>,
|
video_loop: Option<bool>,
|
||||||
video_start_time: Option<f32>,
|
video_start_time: Option<f32>,
|
||||||
video_end_time: Option<f32>,
|
video_end_time: Option<f32>,
|
||||||
|
pdf_index: Option<u32>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
text_svg: Option<TextSvg>,
|
text_svg: Option<TextSvg>,
|
||||||
}
|
}
|
||||||
|
@ -607,6 +629,14 @@ impl SlideBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pdf_index(
|
||||||
|
mut self,
|
||||||
|
pdf_index: impl Into<u32>,
|
||||||
|
) -> Self {
|
||||||
|
let _ = self.pdf_index.insert(pdf_index.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn build(self) -> Result<Slide> {
|
pub(crate) fn build(self) -> Result<Slide> {
|
||||||
let Some(background) = self.background else {
|
let Some(background) = self.background else {
|
||||||
return Err(miette!("No background"));
|
return Err(miette!("No background"));
|
||||||
|
@ -643,6 +673,7 @@ impl SlideBuilder {
|
||||||
video_start_time,
|
video_start_time,
|
||||||
video_end_time,
|
video_end_time,
|
||||||
text_svg: self.text_svg,
|
text_svg: self.text_svg,
|
||||||
|
pdf_index: self.pdf_index.unwrap_or_default(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,26 +11,42 @@ use miette::Severity;
|
||||||
use mupdf::Colorspace;
|
use mupdf::Colorspace;
|
||||||
use mupdf::Document;
|
use mupdf::Document;
|
||||||
use mupdf::Matrix;
|
use mupdf::Matrix;
|
||||||
use mupdf::Page;
|
use tracing::debug;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct PdfViewer {
|
pub struct PdfViewer {
|
||||||
document: Option<Document>,
|
document: Option<Document>,
|
||||||
pages: Option<Vec<Page>>,
|
pages: Option<Vec<Handle>>,
|
||||||
current_page: Option<Page>,
|
current_page: Option<Handle>,
|
||||||
current_index: usize,
|
current_index: usize,
|
||||||
handle: Option<Handle>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Message {}
|
pub enum Message {}
|
||||||
|
|
||||||
impl PdfViewer {
|
impl PdfViewer {
|
||||||
pub fn with_pdf(pdf: impl AsRef<Path>) -> Result<Self> {
|
pub fn with_pdf(pdf: impl AsRef<Path>) -> Result<Self> {
|
||||||
let pdf_path = pdf.as_ref();
|
let pdf_path = pdf.as_ref();
|
||||||
let document = Document::open(pdf_path).into_diagnostic()?;
|
let document = Document::open(pdf_path).into_diagnostic()?;
|
||||||
let pages = document.pages().into_diagnostic()?;
|
let pages = document.pages().into_diagnostic()?;
|
||||||
let pages: Vec<Page> =
|
let pages: Vec<Handle> = pages
|
||||||
pages.filter_map(|page| page.ok()).collect();
|
.filter_map(|page| {
|
||||||
|
let Some(page) = page.ok() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let matrix = Matrix::IDENTITY;
|
||||||
|
let colorspace = Colorspace::device_rgb();
|
||||||
|
let Ok(pixmap) = page
|
||||||
|
.to_pixmap(&matrix, &colorspace, true, true)
|
||||||
|
.into_diagnostic()
|
||||||
|
else {
|
||||||
|
error!("Can't turn this page into pixmap");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let handle = pixmap.samples().to_vec();
|
||||||
|
Some(Handle::from_bytes(handle))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let Some(page) = document.pages().into_diagnostic()?.next()
|
let Some(page) = document.pages().into_diagnostic()?.next()
|
||||||
else {
|
else {
|
||||||
return Err(miette::miette!(
|
return Err(miette::miette!(
|
||||||
|
@ -48,9 +64,8 @@ impl PdfViewer {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
document: Some(document),
|
document: Some(document),
|
||||||
pages: Some(pages),
|
pages: Some(pages),
|
||||||
current_page: Some(page),
|
|
||||||
current_index: 0,
|
current_index: 0,
|
||||||
handle: Some(Handle::from_bytes(handle)),
|
current_page: Some(Handle::from_bytes(handle)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +76,29 @@ impl PdfViewer {
|
||||||
let pdf_path = pdf.as_ref();
|
let pdf_path = pdf.as_ref();
|
||||||
let document = Document::open(pdf_path).into_diagnostic()?;
|
let document = Document::open(pdf_path).into_diagnostic()?;
|
||||||
let pages = document.pages().into_diagnostic()?;
|
let pages = document.pages().into_diagnostic()?;
|
||||||
let pages: Vec<Page> =
|
|
||||||
pages.filter_map(|page| page.ok()).collect();
|
let pages: Vec<Handle> = pages
|
||||||
|
.filter_map(|page| {
|
||||||
|
let Some(page) = page.ok() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let matrix = Matrix::IDENTITY;
|
||||||
|
let colorspace = Colorspace::device_rgb();
|
||||||
|
let Ok(pixmap) = page
|
||||||
|
.to_pixmap(&matrix, &colorspace, true, true)
|
||||||
|
.into_diagnostic()
|
||||||
|
else {
|
||||||
|
error!("Can't turn this page into pixmap");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
debug!(?pixmap);
|
||||||
|
Some(Handle::from_rgba(
|
||||||
|
pixmap.width(),
|
||||||
|
pixmap.height(),
|
||||||
|
pixmap.samples().to_vec(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let Some(page) = document.pages().into_diagnostic()?.next()
|
let Some(page) = document.pages().into_diagnostic()?.next()
|
||||||
else {
|
else {
|
||||||
return Err(miette::miette!(
|
return Err(miette::miette!(
|
||||||
|
@ -70,18 +106,11 @@ impl PdfViewer {
|
||||||
"There isn't a first page here"
|
"There isn't a first page here"
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let page = page.into_diagnostic()?;
|
self.current_page = pages.get(0).map(|h| h.to_owned());
|
||||||
let matrix = Matrix::IDENTITY;
|
|
||||||
let colorspace = Colorspace::device_rgb();
|
|
||||||
let pixmap = page
|
|
||||||
.to_pixmap(&matrix, &colorspace, true, true)
|
|
||||||
.into_diagnostic()?;
|
|
||||||
let handle = pixmap.samples().to_vec();
|
|
||||||
self.document = Some(document);
|
self.document = Some(document);
|
||||||
self.pages = Some(pages);
|
self.pages = Some(pages);
|
||||||
self.current_page = Some(page);
|
|
||||||
self.current_index = 0;
|
self.current_index = 0;
|
||||||
self.handle = Some(Handle::from_bytes(handle));
|
debug!(?self);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,15 +121,8 @@ impl PdfViewer {
|
||||||
let Some(page) = pages.get(self.current_index + 1) else {
|
let Some(page) = pages.get(self.current_index + 1) else {
|
||||||
return Err(miette::miette!("There isn't a next page"));
|
return Err(miette::miette!("There isn't a next page"));
|
||||||
};
|
};
|
||||||
let matrix = Matrix::IDENTITY;
|
|
||||||
let colorspace = Colorspace::device_rgb();
|
|
||||||
let pixmap = page
|
|
||||||
.to_pixmap(&matrix, &colorspace, true, true)
|
|
||||||
.into_diagnostic()?;
|
|
||||||
let handle = pixmap.samples().to_vec();
|
|
||||||
self.current_page = Some(page.to_owned());
|
self.current_page = Some(page.to_owned());
|
||||||
self.current_index += 1;
|
self.current_index += 1;
|
||||||
self.handle = Some(Handle::from_bytes(handle));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,20 +138,16 @@ impl PdfViewer {
|
||||||
"There isn't a previous page"
|
"There isn't a previous page"
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let matrix = Matrix::IDENTITY;
|
|
||||||
let colorspace = Colorspace::device_rgb();
|
|
||||||
let pixmap = page
|
|
||||||
.to_pixmap(&matrix, &colorspace, true, true)
|
|
||||||
.into_diagnostic()?;
|
|
||||||
let handle = pixmap.samples().to_vec();
|
|
||||||
self.current_page = Some(page.to_owned());
|
self.current_page = Some(page.to_owned());
|
||||||
self.current_index -= 1;
|
self.current_index -= 1;
|
||||||
self.handle = Some(Handle::from_bytes(handle));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Option<Element<Message>> {
|
pub fn view(&self, index: u32) -> Option<Element<Message>> {
|
||||||
let Some(handle) = self.handle.clone() else {
|
let Some(pages) = &self.pages else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(handle) = pages.get(index as usize) else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some(
|
Some(
|
||||||
|
|
|
@ -174,6 +174,7 @@ impl Presenter {
|
||||||
},
|
},
|
||||||
scroll_id: Id::unique(),
|
scroll_id: Id::unique(),
|
||||||
current_font: cosmic::font::default(),
|
current_font: cosmic::font::default(),
|
||||||
|
pdf_viewer: PdfViewer::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +207,8 @@ impl Presenter {
|
||||||
Message::SlideChange(slide) => {
|
Message::SlideChange(slide) => {
|
||||||
let slide_text = slide.text();
|
let slide_text = slide.text();
|
||||||
debug!(slide_text, "slide changed");
|
debug!(slide_text, "slide changed");
|
||||||
debug!("comparing background...");
|
let bg = slide.background().clone();
|
||||||
|
debug!(?bg, "comparing background...");
|
||||||
let backgrounds_match =
|
let backgrounds_match =
|
||||||
self.current_slide.background()
|
self.current_slide.background()
|
||||||
== slide.background();
|
== slide.background();
|
||||||
|
@ -223,6 +225,11 @@ impl Presenter {
|
||||||
self.reset_video();
|
self.reset_video();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if slide.background().kind == BackgroundKind::Pdf {
|
||||||
|
self.pdf_viewer
|
||||||
|
.insert_pdf(&slide.background().path);
|
||||||
|
}
|
||||||
|
|
||||||
let offset = AbsoluteOffset {
|
let offset = AbsoluteOffset {
|
||||||
x: {
|
x: {
|
||||||
if self.current_slide_index > 2 {
|
if self.current_slide_index > 2 {
|
||||||
|
@ -404,6 +411,7 @@ impl Presenter {
|
||||||
slide_view(
|
slide_view(
|
||||||
&self.current_slide,
|
&self.current_slide,
|
||||||
&self.video,
|
&self.video,
|
||||||
|
&self.pdf_viewer,
|
||||||
self.current_font,
|
self.current_font,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
@ -414,6 +422,7 @@ impl Presenter {
|
||||||
slide_view(
|
slide_view(
|
||||||
&self.current_slide,
|
&self.current_slide,
|
||||||
&self.video,
|
&self.video,
|
||||||
|
&self.pdf_viewer,
|
||||||
self.current_font,
|
self.current_font,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
@ -450,6 +459,7 @@ impl Presenter {
|
||||||
let container = slide_view(
|
let container = slide_view(
|
||||||
&slide,
|
&slide,
|
||||||
&self.video,
|
&self.video,
|
||||||
|
&self.pdf_viewer,
|
||||||
font,
|
font,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -636,7 +646,6 @@ impl Presenter {
|
||||||
|
|
||||||
fn reset_video(&mut self) {
|
fn reset_video(&mut self) {
|
||||||
match self.current_slide.background().kind {
|
match self.current_slide.background().kind {
|
||||||
BackgroundKind::Image => self.video = None,
|
|
||||||
BackgroundKind::Video => {
|
BackgroundKind::Video => {
|
||||||
let path = &self.current_slide.background().path;
|
let path = &self.current_slide.background().path;
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
@ -660,6 +669,7 @@ impl Presenter {
|
||||||
self.video = None;
|
self.video = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => self.video = None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,6 +722,7 @@ fn scale_font(font_size: f32, width: f32) -> f32 {
|
||||||
pub(crate) fn slide_view<'a>(
|
pub(crate) fn slide_view<'a>(
|
||||||
slide: &'a Slide,
|
slide: &'a Slide,
|
||||||
video: &'a Option<Video>,
|
video: &'a Option<Video>,
|
||||||
|
pdf_viewer: &'a PdfViewer,
|
||||||
font: Font,
|
font: Font,
|
||||||
delegate: bool,
|
delegate: bool,
|
||||||
hide_mouse: bool,
|
hide_mouse: bool,
|
||||||
|
@ -788,6 +799,18 @@ pub(crate) fn slide_view<'a>(
|
||||||
Container::new(Space::new(0, 0))
|
Container::new(Space::new(0, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BackgroundKind::Pdf => Container::new(
|
||||||
|
if let Some(pdf) = pdf_viewer.view(slide.pdf_index())
|
||||||
|
{
|
||||||
|
pdf.map(|_| Message::None)
|
||||||
|
} else {
|
||||||
|
Space::new(0.0, 0.0).into()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.center_x(width)
|
||||||
|
.center_y(size.height)
|
||||||
|
.clip(true),
|
||||||
|
BackgroundKind::Html => todo!(),
|
||||||
};
|
};
|
||||||
let stack = stack!(
|
let stack = stack!(
|
||||||
black,
|
black,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
(slide (video :source "~/vids/test/camprules2024.mp4" :fit contain))
|
(slide (video :source "~/vids/test/camprules2024.mp4" :fit contain))
|
||||||
;; (slide (video :source "~/vids/never give up.mkv" :fit contain))
|
;; (slide (video :source "~/vids/never give up.mkv" :fit contain))
|
||||||
;; (slide (video :source "~/vids/The promise of Rust.mkv" :fit contain))
|
;; (slide (video :source "~/vids/The promise of Rust.mkv" :fit contain))
|
||||||
|
(slide :background (presentation :source "~/docs/description-of-a-discipled-person-assessment-2016.pdf" :fit contain))
|
||||||
(song :id 7 :author "North Point Worship"
|
(song :id 7 :author "North Point Worship"
|
||||||
:font "Quicksand" :font-size 120
|
:font "Quicksand" :font-size 120
|
||||||
:shadow "" :stroke ""
|
:shadow "" :stroke ""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue