diff --git a/TODO.org b/TODO.org index ec9e3f0..8f87e68 100644 --- a/TODO.org +++ b/TODO.org @@ -67,6 +67,8 @@ Once the model of OBS scenes is created, we can select a scene to add it to the *** TODO This should be ported to slides rather than service_items. Since sometimes in a presentation you'd possibly want different obs scenes, lets instead make these changes on the slides rather than on the service_items. That way each slide can have an associated obs scene and do some trickerydo to determine if we need to change it. +I need to properly update them yet, it would seem I never assigned the obs scene to the slides and then obs wouldn't have anything to change to. I'm trying to change it now. + *** TODO OBWS setting scenes This has been really tricky since there is something of a bug when using =runtime.block_on()= rather than having a single cohesive tokio runtime. So, perhaps I need to figure out if I can't make a runtime that works for the whole app so that I can manage these a little better. diff --git a/src/qml/presenter/MainWindow.qml b/src/qml/presenter/MainWindow.qml index 087cb0c..f90d7d9 100644 --- a/src/qml/presenter/MainWindow.qml +++ b/src/qml/presenter/MainWindow.qml @@ -314,7 +314,7 @@ Controls.Page { editMode = false; refocusPresentation(); footerFirstText = presenting ? "Presenting..." : "Presentation Preview"; - footerSecondText = ""; + footerSecondText = ObsModel.currentProgramScene; } } else { videoEditor.visible = false; @@ -327,7 +327,7 @@ Controls.Page { editMode = false; refocusPresentation(); footerFirstText = presenting ? "Presenting..." : "Presentation Preview" - footerSecondText = ""; + footerSecondText = ObsModel.currentProgramScene; } } diff --git a/src/qml/presenter/PreviewSlideListDelegate.qml b/src/qml/presenter/PreviewSlideListDelegate.qml index a400507..9b4420c 100644 --- a/src/qml/presenter/PreviewSlideListDelegate.qml +++ b/src/qml/presenter/PreviewSlideListDelegate.qml @@ -11,6 +11,7 @@ Item { implicitHeight: Kirigami.Units.gridUnit * 6.5 implicitWidth: Kirigami.Units.gridUnit * 9 property bool showVidBG + property var rootModel: model /* property var previewSlidesList: parent */ /* Component.onCompleted: { */ /* if (model.videoBackground != "") */ @@ -75,14 +76,23 @@ Item { Controls.Label { id: obsSceneLabel - width: previewHighlight.width - anchors.top: previewHighlight.bottom - anchors.left: previewHighlight.left + anchors.top: previewHighlight.top + anchors.right: previewHighlight.right anchors.topMargin: Kirigami.Units.smallSpacing - anchors.rightMargin: Kirigami.Units.smallSpacing * 2 - elide: Text.ElideRight - text: model.obsScene - font.bold: true + anchors.rightMargin: Kirigami.Units.smallSpacing + /* elide: Text.ElideRight */ + background: Rectangle { + visible: model.obsScene.length > 0 + color: Qt.lighter(Kirigami.Theme.backgroundColor, 1.2) + radius: 3 + } + + horizontalAlignment: Text.AlignRight + text: model.obsScene.length > 0 ? "OBS Scene: " + model.obsScene : "" + font.pointSize: 8 + rightPadding: 4 + leftPadding: 4 + color: Kirigami.Theme.highlightColor } MouseArea { @@ -101,9 +111,9 @@ Item { cursorShape: Qt.PointingHandCursor propagateComposedEvents: true - Controls.ToolTip { - text: model.obsScene - } + /* Controls.ToolTip { */ + /* text: model.obsScene.length > 0 ? "OBS Scene: " + model.obsScene : "" */ + /* } */ } @@ -119,10 +129,10 @@ Item { Kirigami.Action { text: modelData onTriggered: { - Utils.dbg("setting: " + modelData) - Utils.dbg(model.obsScene); - SlideModel.updateObsScene(modelData); - /* ObsModel.setScene(modelData); */ + Utils.dbg("setting: " + modelData + " on index: " + rootModel.index); + Utils.dbg(rootModel.obsScene); + SlideModel.updateObsScene(rootModel.index, modelData); + ObsModel.setScene(modelData); } } onObjectAdded: obsMenu.insertAction(index, object) diff --git a/src/rust/obs.rs b/src/rust/obs.rs index 9afc7af..433568a 100644 --- a/src/rust/obs.rs +++ b/src/rust/obs.rs @@ -75,31 +75,33 @@ impl Obs { } pub fn set_scene( - self, + &self, scene: String, ) -> Result<(), Box> { - debug!("Starting function"); - if let Some(client) = self.client { - debug!("Starting to set"); - let runtime = - tokio::runtime::Builder::new_current_thread() - .thread_keep_alive(Duration::from_secs(1)) - .enable_all() - .build() - .unwrap(); + // debug!("Starting function"); + if let Some(client) = &self.client { + debug!(scene, "setting scene in obs"); + let client = make_client(); - let handle = runtime.spawn(async move { - debug!(scene, "working in thread"); - client.scenes() - .set_current_program_scene(&scene) - .await - }); - loop { - sleep(Duration::from_millis(100)); - if handle.is_finished() { - break; + let runtime = tokio::runtime::Runtime::new()?; + let handle = runtime.spawn(async move { + debug!("in spawn: before setting"); + let res = client.scenes().set_current_program_scene(&scene).await; + match res { + Ok(o) => debug!("in spawn: after setting: success"), + Err(e) => error!(?e, "in spawn: after setting") } - } + }); + + debug!("after spawn"); + + // loop { + // sleep(Duration::from_millis(100)); + // if handle.is_finished() { + // break; + // } + // } + Ok(()) } else { Err("There is no client".to_owned())? @@ -180,13 +182,13 @@ impl obs_model::ObsModel { tokio::runtime::Runtime::new().unwrap().block_on(async { match Obs::new().await { Ok(o) => { + if let Some(scene) = &o.current_program_scene { + let scene = QString::from(scene); + self.as_mut().set_current_program_scene(scene); + } self.as_mut().set_connected(true); self.as_mut().rust_mut().obs = Some(o); self.as_mut().update_scenes(); - if let Some(scene) = o.current_program_scene { - let scene = QString::from(&scene); - self.as_mut().set_current_program_scene(scene); - } } Err(e) => { error!(e); @@ -220,6 +222,11 @@ mod test { #[test] pub fn test_obs_setting_scene() { - assert_eq!(true, true) + let runtime = tokio::runtime::Runtime::new().unwrap(); + let future = Client::connect("localhost", 4455, Some("")); + let client = runtime.block_on(future).unwrap(); + let scene = String::from("me"); + let res = runtime.block_on(client.scenes().set_current_program_scene(&scene)); + debug_assert!(res.is_ok()); } } diff --git a/src/rust/slide_model.rs b/src/rust/slide_model.rs index 90ced01..1077e2f 100644 --- a/src/rust/slide_model.rs +++ b/src/rust/slide_model.rs @@ -47,6 +47,7 @@ mod slide_model { VideoStartTime, VideoEndTime, Html, + ObsScene, } unsafe extern "RustQt" { @@ -123,6 +124,13 @@ mod slide_model { #[qinvokable] fn activate(self: Pin<&mut SlideModel>, index: i32) -> bool; + + #[qinvokable] + fn update_obs_scene( + self: Pin<&mut SlideModel>, + index: i32, + obs_scene: QString, + ); } impl cxx_qt::Threading for SlideModel {} @@ -271,7 +279,7 @@ impl Default for Slide { } } -#[derive(Default, Debug)] +#[derive(Debug)] pub struct SlideModelRust { id: i32, slides: Vec, @@ -279,6 +287,28 @@ pub struct SlideModelRust { count: i32, } + +impl Default for SlideModelRust { + fn default() -> Self { + let obs = + tokio::runtime::Runtime::new().unwrap().block_on(async { + match Obs::new().await { + Ok(o) => Some(o), + Err(e) => { + error!(e); + None + } + } + }); + Self { + id: 0, + slides: Vec::new(), + obs, + count: 0, + } + } +} + impl slide_model::SlideModel { pub fn add_video_thumbnail( mut self: Pin<&mut Self>, @@ -1154,25 +1184,26 @@ impl slide_model::SlideModel { slide.active = false; } - let obs = self.as_mut().obs.clone(); - if let Some(slide) = self.as_mut().rust_mut().slides.get_mut(index as usize) { debug!( slide = index, service_item = slide.service_item_id, + obs = slide.obs_scene.to_string(), "This slide is activating" ); let obs_scene = slide.obs_scene.to_string(); slide.active = true; self.as_mut().data_changed(tl, br, &vector_roles); - if let Some(obs) = obs { + if let Some(obs) = self.as_ref().obs.clone() { match obs.set_scene(obs_scene) { Ok(()) => debug!("Successfully set scene"), Err(e) => error!(e), } + } else { + debug!("Obs isn't connected"); } // We use this signal generated by our signals enum to tell QML that @@ -1184,6 +1215,24 @@ impl slide_model::SlideModel { } } + pub fn update_obs_scene( + mut self: Pin<&mut Self>, + index: i32, + obs_scene: QString, + ) { + let rc = self.as_ref().count() - 1; + let tl = &self.as_ref().index(0, 0, &QModelIndex::default()); + let br = &self.as_ref().index(rc, 0, &QModelIndex::default()); + let mut vector_roles = QVector_i32::default(); + vector_roles.append(self.get_role(SlideRoles::ObsScene)); + if let Some(slide) = + self.as_mut().rust_mut().slides.get_mut(index as usize) + { + slide.obs_scene = obs_scene; + self.as_mut().data_changed(tl, br, &vector_roles); + } + } + fn get_role(&self, role: SlideRoles) -> i32 { match role { SlideRoles::Text => 1, @@ -1193,6 +1242,8 @@ impl slide_model::SlideModel { SlideRoles::VideoThumbnail => 15, SlideRoles::VideoStartTime => 16, SlideRoles::VideoEndTime => 17, + SlideRoles::Html => 18, + SlideRoles::ObsScene => 19, _ => 0, } } @@ -1247,6 +1298,9 @@ impl slide_model::SlideModel { QVariant::from(&slide.video_end_time) } SlideRoles::Html => QVariant::from(&slide.html), + SlideRoles::ObsScene => { + QVariant::from(&slide.obs_scene) + } _ => QVariant::default(), }; } @@ -1325,6 +1379,10 @@ impl slide_model::SlideModel { QByteArray::from("videoEndTime"), ); roles.insert(SlideRoles::Html.repr, QByteArray::from("html")); + roles.insert( + SlideRoles::ObsScene.repr, + QByteArray::from("obsScene"), + ); roles } @@ -1334,3 +1392,13 @@ impl slide_model::SlideModel { cnt } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + pub fn test_obs_setting_scene() { + assert_eq!(true, true) + } +}