From c60353f8c81b62f738e8c349f920edca2010e4d5 Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Tue, 19 Nov 2024 12:35:42 -0600 Subject: [PATCH] Getting closer to a working little system --- Cargo.lock | 83 +++++++++++++++++ Cargo.toml | 1 + justfile | 4 +- src/core/slide.rs | 35 ++++++- src/lisp.rs | 14 +++ src/main.rs | 131 +++++++++++++++++++++------ src/ui/mod.rs | 1 - src/ui/presenter.rs | 196 +++++++++++++++++++++------------------- src/ui/slide_preview.rs | 5 - 9 files changed, 338 insertions(+), 132 deletions(-) create mode 100644 src/lisp.rs delete mode 100644 src/ui/slide_preview.rs diff --git a/Cargo.lock b/Cargo.lock index 833e761..9268f92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1254,6 +1254,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crisp" +version = "0.1.0" +source = "git+https://git.tfcconnection.org/chris/crisp#04a470d771bd86646d27ef35811fc7d6a3c7bafb" +dependencies = [ + "lazy_static", + "miette", + "pretty_assertions", + "regex", + "rustyline", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -1591,6 +1603,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "enumflags2" version = "0.7.10" @@ -1739,6 +1757,17 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[package]] +name = "fd-lock" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +dependencies = [ + "cfg-if", + "rustix 0.38.37", + "windows-sys 0.52.0", +] + [[package]] name = "fdeflate" version = "0.3.5" @@ -3268,6 +3297,7 @@ name = "lumina" version = "0.1.0" dependencies = [ "clap", + "crisp", "dirs", "iced_video_player", "lexpr", @@ -3582,6 +3612,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "nix" version = "0.26.4" @@ -3594,6 +3633,18 @@ dependencies = [ "memoffset 0.7.1", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases 0.1.1", + "libc", +] + [[package]] name = "nix" version = "0.29.0" @@ -4493,6 +4544,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.8.5" @@ -4823,6 +4884,28 @@ dependencies = [ "unicode-script", ] +[[package]] +name = "rustyline" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix 0.28.0", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index e04efce..807d0a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,4 @@ ron = "0.8.1" sqlx = { version = "0.8.2", features = ["sqlite"] } dirs = "5.0.1" tokio = "1.41.1" +crisp = { git = "https://git.tfcconnection.org/chris/crisp" } diff --git a/justfile b/justfile index d9b29f9..c70b6bd 100644 --- a/justfile +++ b/justfile @@ -2,8 +2,8 @@ default: just --list build: RUST_LOG=debug cargo build -run: - RUST_LOG=debug cargo run -- -i ~/dev/lumina-iced/test_presentation.lisp +run ui=' ' file='~/dev/lumina-iced/test_presentation.lisp': + RUST_LOG=debug cargo run -- {{ui}} {{file}} clean: RUST_LOG=debug cargo clean test: diff --git a/src/core/slide.rs b/src/core/slide.rs index 351c61f..9e450ba 100644 --- a/src/core/slide.rs +++ b/src/core/slide.rs @@ -1,7 +1,4 @@ -use lexpr::{ - parse::{from_str_elisp, Options}, - Parser, Value, -}; +use crisp::types::{Keyword, Value}; use miette::{miette, IntoDiagnostic, Result}; use serde::{Deserialize, Serialize}; use std::{ @@ -187,6 +184,36 @@ impl Slide { } } +impl From for Slide { + fn from(value: Value) -> Self { + match value { + Value::List(list) => lisp_to_slide(list), + _ => Slide::default(), + } + } +} + +fn lisp_to_slide(lisp: Vec) -> Slide { + let mut slide = SlideBuilder::new(); + let background_position = if let Some(background) = + lisp.position(|v| Value::Keyword(Keyword::from("background"))) + { + background + 1 + } else { + 0 + }; + + if let Some(background) = lisp.get(background_position) { + slide.background(lisp_to_background(background)); + } else { + slide.background(Background::default()); + } +} + +fn lisp_to_background(lisp: &Value) { + todo!() +} + #[derive( Clone, Debug, Default, PartialEq, Serialize, Deserialize, )] diff --git a/src/lisp.rs b/src/lisp.rs new file mode 100644 index 0000000..3ed0172 --- /dev/null +++ b/src/lisp.rs @@ -0,0 +1,14 @@ +use crisp::{ + env::Environment, + types::{Symbol, Value}, +}; + +use crate::{Slide, SlideBuilder}; + +pub fn setup_env() { + let mut env = Environment::new(); + env.insert_symbol( + Symbol::from("slide"), + Value::func(|args| Ok(Value::from(args))), + ) +} diff --git a/src/main.rs b/src/main.rs index 684dce9..be4c4b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,25 @@ use clap::{command, Parser}; use cosmic::app::{Core, Settings, Task}; -use cosmic::dialog::ashpd::url::Url; use cosmic::iced::keyboard::Key; use cosmic::iced::window::Position; -use cosmic::iced::{ - self, event, window, ContentFit, Font, Length, Point, -}; +use cosmic::iced::{self, event, window, Font, Length, Point}; use cosmic::iced_core::SmolStr; use cosmic::iced_widget::{column, row, stack}; -use cosmic::widget::icon; +use cosmic::prelude::*; use cosmic::widget::tooltip::Position as TPosition; -use cosmic::widget::{button, image, nav_bar, text, tooltip, Space}; +use cosmic::widget::{ + button, image, nav_bar, text, tooltip, Responsive, Space, +}; +use cosmic::widget::{icon, slider}; use cosmic::{executor, Application, ApplicationExt, Element}; use cosmic::{widget::Container, Theme}; -use iced_video_player::{Video, VideoPlayer}; use miette::{miette, Result}; use std::path::PathBuf; -use tracing::error; use tracing::{debug, level_filters::LevelFilter}; use tracing_subscriber::EnvFilter; pub mod core; +pub mod lisp; pub mod ui; use core::slide::*; use ui::presenter::{self, Presenter}; @@ -93,7 +92,7 @@ impl Default for App { .build() .expect("oops slide"); let slides = vec![initial_slide.clone()]; - let presenter = Presenter::with_app_slides(slides.clone()); + let presenter = Presenter::with_slides(slides.clone()); Self { presenter, core: Core::default(), @@ -152,7 +151,7 @@ impl cosmic::Application for App { .unwrap(), ) .expect("oops video") - .text("Hello") + .text("") .font("Quicksand") .font_size(50) .text_alignment(TextAlignment::MiddleCenter) @@ -179,12 +178,26 @@ impl cosmic::Application for App { .build() .expect("oops slide"); - let slides = vec![ - initial_slide.clone(), - second_slide.clone(), - second_slide.clone(), - ]; - let presenter = Presenter::with_app_slides(slides.clone()); + let tetrary_slide = SlideBuilder::new() + .background( + PathBuf::from("/home/chris/pics/wojaks/reddit_the_xenomorph_s bigass wojak folder/Chads/ChristianChad_x16_drawing.png") + .canonicalize() + .unwrap(), + ) + .expect("oops video") + .text("Hello") + .font("Quicksand") + .font_size(50) + .text_alignment(TextAlignment::MiddleCenter) + .video_loop(false) + .video_start_time(0.0) + .video_end_time(0.0) + .build() + .expect("oops slide"); + + let slides = + vec![initial_slide.clone(), second_slide, tetrary_slide]; + let presenter = Presenter::with_slides(slides.clone()); let mut app = App { presenter, core, @@ -347,7 +360,7 @@ impl cosmic::Application for App { ) -> cosmic::Task> { match message { Message::Present(message) => { - self.presenter.update(message); + let _ = self.presenter.update(message); // self.core.nav_bar_toggle(); Task::none() } @@ -403,9 +416,47 @@ impl cosmic::Application for App { // Main window view fn view(&self) -> Element { debug!("Main view"); - let preview = self.presenter.view(); let icon_left = icon::from_name("arrow-left"); let icon_right = icon::from_name("arrow-right"); + + let video_range: f32 = + if let Some(video) = &self.presenter.video { + let duration = video.duration(); + duration.as_secs_f32() + } else { + 0.0 + }; + + let video_pos = if let Some(video) = &self.presenter.video { + let range = video.position(); + range.as_secs_f32() + } else { + 0.0 + }; + + let video_button_icon = + if let Some(video) = &self.presenter.video { + if video.paused() { + button::icon(icon::from_name("media-play")) + .tooltip("Play") + .on_press(Message::Present( + presenter::Message::StartVideo, + )) + } else { + button::icon(icon::from_name("media-pause")) + .tooltip("Pause") + .on_press(Message::Present( + presenter::Message::StartVideo, + )) + } + } else { + button::icon(icon::from_name("media-play")) + .tooltip("Play") + .on_press(Message::Present( + presenter::Message::StartVideo, + )) + }; + let row = row![ Container::new( button::icon(icon_left) @@ -419,13 +470,43 @@ impl cosmic::Application for App { .center_y(Length::Fill) .align_right(Length::Fill) .width(Length::FillPortion(1)), - Container::new( - Container::new(preview.map(|m| Message::Present(m))) - .center(Length::Fill) - .max_height(270) - ) + Container::new(column![ + Space::with_height(Length::Fill), + Responsive::new(move |size| { + let height = size.width * 9.0 / 16.0; + Container::new( + self.presenter + .view() + .map(|m| Message::Present(m)), + ) + .width(Length::Fill) + .height(height) + .into() + }), + Container::new( + row![ + video_button_icon, + Container::new(slider( + 0.0..=video_range, + video_pos, + |pos| { + Message::Present( + presenter::Message::VideoPos(pos), + ) + } + )) + .center_x(Length::Fill) + .padding([7, 0, 0, 0]) + ] + .padding(5) + ) + .align_top(Length::Shrink) + .height(Length::Shrink) + .center_x(Length::Fill), + Space::with_height(Length::Fill) + ]) .center_y(Length::Fill) - .width(Length::FillPortion(3)), + .center_x(Length::FillPortion(3)), Container::new( button::icon(icon_right) .icon_size(128) @@ -526,7 +607,6 @@ fn test_slide<'a>() -> Element<'a, Message> { #[cfg(test)] mod test { - use super::*; use pretty_assertions::assert_eq; @@ -539,7 +619,6 @@ mod test { // fn test_lisp() { // let slide = test_slide(); // if let Ok(data) = lexpr::parse::from_str_elisp(slide.as_str()) { - // println!("{data:?}"); // assert_eq!(slide, data) // } else { // assert!(false) diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 0ff54bb..642e8f7 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,2 +1 @@ pub mod presenter; -pub mod slide_preview; diff --git a/src/ui/presenter.rs b/src/ui/presenter.rs index ba28ece..118bba2 100644 --- a/src/ui/presenter.rs +++ b/src/ui/presenter.rs @@ -1,40 +1,43 @@ -use std::{path::PathBuf, rc::Rc}; +use std::{path::PathBuf, rc::Rc, time::Duration}; use cosmic::{ dialog::ashpd::url::Url, - iced::{widget::text, ContentFit, Length}, - iced_widget::{row, stack, Stack}, + iced::{widget::text, Background, Color, ContentFit, Length}, + iced_widget::stack, prelude::*, - widget::{ - button, container, icon::Named, image, Container, Row, Space, - }, + widget::{container, image, Container, Row, Space}, Task, }; -use iced_video_player::{Video, VideoPlayer}; +use iced_video_player::{Position, Video, VideoPlayer}; use miette::{Context, IntoDiagnostic, Result}; -use tracing::{debug, error}; +use tracing::{debug, error, info}; use crate::{core::slide::Slide, BackgroundKind}; // #[derive(Default, Clone, Debug)] pub(crate) struct Presenter { pub slides: Vec, - pub current_slide: i16, + pub current_slide: Slide, + pub current_slide_index: u16, pub video: Option