update slides and songs to generate strokes and shadows in text_svg
Some checks are pending
/ test (push) Waiting to run

This commit is contained in:
Chris Cochrun 2026-02-11 06:25:55 -06:00
parent 3b960c5a17
commit 4bd8cf04d4
5 changed files with 193 additions and 80 deletions

View file

@ -1,6 +1,4 @@
use cosmic::{
cosmic_theme::palette::rgb::Rgba, widget::image::Handle,
};
use cosmic::widget::image::Handle;
// use cosmic::dialog::ashpd::url::Url;
use crisp::types::{Keyword, Symbol, Value};
use iced_video_player::Video;
@ -12,7 +10,7 @@ use std::{
};
use tracing::error;
use crate::ui::text_svg::{Shadow, Stroke, TextSvg};
use crate::ui::text_svg::{Color, Font, Shadow, Stroke, TextSvg};
use super::songs::Song;
@ -23,11 +21,12 @@ pub struct Slide {
id: i32,
pub(crate) background: Background,
text: String,
font: String,
font: Option<Font>,
font_size: i32,
stroke: Option<Stroke>,
shadow: Option<Shadow>,
text_alignment: TextAlignment,
text_color: Option<Color>,
audio: Option<PathBuf>,
video_loop: bool,
video_start_time: f32,
@ -280,7 +279,7 @@ impl Slide {
}
pub fn set_font(mut self, font: impl AsRef<str>) -> Self {
self.font = font.as_ref().into();
self.font = Some(font.as_ref().into());
self
}
@ -315,7 +314,7 @@ impl Slide {
self.font_size
}
pub fn font(&self) -> String {
pub fn font(&self) -> Option<Font> {
self.font.clone()
}
@ -331,6 +330,18 @@ impl Slide {
self.pdf_page.clone()
}
pub fn text_color(&self) -> Option<Color> {
self.text_color.clone()
}
pub fn stroke(&self) -> Option<Stroke> {
self.stroke.clone()
}
pub fn shadow(&self) -> Option<Shadow> {
self.shadow.clone()
}
pub const fn pdf_index(&self) -> u32 {
self.pdf_index
}
@ -543,9 +554,12 @@ pub fn lisp_to_background(lisp: &Value) -> Background {
pub struct SlideBuilder {
background: Option<Background>,
text: Option<String>,
font: Option<String>,
font: Option<Font>,
font_size: Option<i32>,
audio: Option<PathBuf>,
stroke: Option<Stroke>,
shadow: Option<Shadow>,
text_color: Option<Color>,
text_alignment: Option<TextAlignment>,
video_loop: Option<bool>,
video_start_time: Option<f32>,
@ -584,12 +598,20 @@ impl SlideBuilder {
self
}
pub(crate) fn text_color(
mut self,
text_color: impl Into<Color>,
) -> Self {
let _ = self.text_color.insert(text_color.into());
self
}
pub(crate) fn audio(mut self, audio: impl Into<PathBuf>) -> Self {
let _ = self.audio.insert(audio.into());
self
}
pub(crate) fn font(mut self, font: impl Into<String>) -> Self {
pub(crate) fn font(mut self, font: impl Into<Font>) -> Self {
let _ = self.font.insert(font.into());
self
}
@ -599,6 +621,27 @@ impl SlideBuilder {
self
}
pub(crate) fn color(mut self, color: impl Into<Color>) -> Self {
let _ = self.text_color.insert(color.into());
self
}
pub(crate) fn stroke(
mut self,
stroke: impl Into<Stroke>,
) -> Self {
let _ = self.stroke.insert(stroke.into());
self
}
pub(crate) fn shadow(
mut self,
shadow: impl Into<Shadow>,
) -> Self {
let _ = self.shadow.insert(shadow.into());
self
}
pub(crate) fn text_alignment(
mut self,
text_alignment: TextAlignment,
@ -656,9 +699,6 @@ impl SlideBuilder {
let Some(text) = self.text else {
return Err(miette!("No text"));
};
let Some(font) = self.font else {
return Err(miette!("No font"));
};
let Some(font_size) = self.font_size else {
return Err(miette!("No font_size"));
};
@ -677,10 +717,13 @@ impl SlideBuilder {
Ok(Slide {
background,
text,
font,
font: self.font,
font_size,
text_alignment,
audio: self.audio,
stroke: self.stroke,
shadow: self.shadow,
text_color: self.text_color,
video_loop,
video_start_time,
video_end_time,
@ -710,7 +753,7 @@ mod test {
text: "This is frodo".to_string(),
background: Background::try_from("~/pics/frodo.jpg")
.unwrap(),
font: "Quicksand".to_string(),
font: Some("Quicksand".to_string().into()),
font_size: 140,
..Default::default()
}
@ -723,7 +766,7 @@ mod test {
"~/vids/test/camprules2024.mp4",
)
.unwrap(),
font: "Quicksand".to_string(),
font: Some("Quicksand".to_string().into()),
..Default::default()
}
}

View file

@ -3,7 +3,7 @@ use std::{
};
use cosmic::{
cosmic_theme::palette::rgb::Rgba,
cosmic_theme::palette::{IntoColor, Srgb, rgb::Rgba},
iced::clipboard::mime::AsMimeTypes,
};
use crisp::types::{Keyword, Symbol, Value};
@ -16,7 +16,11 @@ use sqlx::{
};
use tracing::{debug, error};
use crate::{Slide, SlideBuilder, core::slide};
use crate::{
Slide, SlideBuilder,
core::slide,
ui::text_svg::{self, Color, Font, Stroke, shadow, stroke},
};
use super::{
content::Content,
@ -41,11 +45,12 @@ pub struct Song {
pub text_alignment: Option<TextAlignment>,
pub font: Option<String>,
pub font_size: Option<i32>,
pub stroke_size: Option<i32>,
pub stroke_color: Option<Rgba>,
pub shadow_size: Option<i32>,
pub shadow_offset: Option<(i32, i32)>,
pub shadow_color: Option<Rgba>,
pub text_color: Option<Srgb>,
pub stroke_size: Option<u16>,
pub stroke_color: Option<Srgb>,
pub shadow_size: Option<u16>,
pub shadow_offset: Option<(i16, i16)>,
pub shadow_color: Option<Srgb>,
pub verses: Option<Vec<VerseName>>,
pub verse_map: Option<HashMap<VerseName, String>>,
}
@ -283,15 +288,58 @@ impl ServiceTrait for Song {
let slides: Vec<Slide> = lyrics
.iter()
.filter_map(|l| {
SlideBuilder::new()
let font =
Font::default()
.name(
self.font
.clone()
.unwrap_or_else(|| "Calibri".into()),
)
.size(self.font_size.unwrap_or_else(|| 100)
as u8);
let stroke_size =
self.stroke_size.unwrap_or_default();
let stroke: Stroke = stroke(
stroke_size,
self.stroke_color
.map(|color| Color::from(color))
.unwrap_or_default(),
);
let shadow_size =
self.shadow_size.unwrap_or_default();
let shadow = shadow(
self.shadow_offset.unwrap_or_default().0,
self.shadow_offset.unwrap_or_default().1,
shadow_size,
self.shadow_color
.map(|color| Color::from(color))
.unwrap_or_default(),
);
let builder = SlideBuilder::new();
let builder = if shadow_size > 0 {
builder.shadow(shadow)
} else {
builder
};
let builder = if stroke_size > 0 {
builder.stroke(stroke)
} else {
builder
};
builder
.background(
self.background.clone().unwrap_or_default(),
)
.font(self.font.clone().unwrap_or_default())
.font(font)
.font_size(self.font_size.unwrap_or_default())
.text_alignment(
self.text_alignment.unwrap_or_default(),
)
.text_color(
self.text_color.unwrap_or_else(|| {
Srgb::new(1.0, 1.0, 1.0)
}),
)
.audio(self.audio.clone().unwrap_or_default())
.video_loop(true)
.video_start_time(0.0)