adding the context_menu for slide_actions

With slide actions, we can ensure certain actions are taken and run
when the slide becomes active.

For now this is only when slides are active, but we can potentially
make sure they run other actions when they are navigated away from
too.
This commit is contained in:
Chris Cochrun 2025-12-15 14:05:36 -06:00
parent ed3ac06d96
commit 66b8ed0c2d

View file

@ -1,7 +1,5 @@
use miette::{IntoDiagnostic, Result}; use miette::{IntoDiagnostic, Result};
use obws::{ use obws::{Client, responses::scenes::Scene};
Client, requests::scenes::SceneId, responses::scenes::Scene,
};
use std::{ use std::{
collections::HashMap, collections::HashMap,
fs::File, fs::File,
@ -25,8 +23,9 @@ use cosmic::{
}, },
prelude::*, prelude::*,
widget::{ widget::{
Container, Id, Row, Space, container, context_menu, icon, Container, Id, Row, Space, container, context_menu,
image, menu, mouse_area, responsive, scrollable, text, horizontal_space, icon, image, menu, mouse_area, responsive,
scrollable, text,
}, },
}; };
use iced_video_player::{Position, Video, VideoPlayer, gst_pbutils}; use iced_video_player::{Position, Video, VideoPlayer, gst_pbutils};
@ -95,11 +94,10 @@ pub(crate) enum Message {
Error(String), Error(String),
None, None,
RightClickSlide(usize, usize), RightClickSlide(usize, usize),
ObsStartStream, AssignObsScene(usize),
ObsStopStream,
ObsSceneAssign(usize),
UpdateObsScenes(Vec<Scene>), UpdateObsScenes(Vec<Scene>),
AddObsClient(Arc<Client>), AddObsClient(Arc<Client>),
AssignSlideAction(slide_actions::Action),
} }
impl std::fmt::Debug for Message { impl std::fmt::Debug for Message {
@ -149,15 +147,17 @@ impl std::fmt::Debug for Message {
.field(arg0) .field(arg0)
.field(arg1) .field(arg1)
.finish(), .finish(),
Self::ObsStartStream => write!(f, "ObsStartStream"), Self::AssignObsScene(arg0) => {
Self::ObsStopStream => write!(f, "ObsStopStream"),
Self::ObsSceneAssign(arg0) => {
f.debug_tuple("ObsSceneAssign").field(arg0).finish() f.debug_tuple("ObsSceneAssign").field(arg0).finish()
} }
Self::UpdateObsScenes(arg0) => { Self::UpdateObsScenes(arg0) => {
f.debug_tuple("UpdateObsScenes").field(arg0).finish() f.debug_tuple("UpdateObsScenes").field(arg0).finish()
} }
Self::AddObsClient(_) => write!(f, "AddObsClient"), Self::AddObsClient(_) => write!(f, "AddObsClient"),
Self::AssignSlideAction(action) => f
.debug_tuple("AssignSlideAction")
.field(action)
.finish(),
} }
} }
} }
@ -177,10 +177,18 @@ impl menu::Action for MenuAction {
fn message(&self) -> Self::Message { fn message(&self) -> Self::Message {
match self { match self {
MenuAction::ObsSceneAssign(scene) => { MenuAction::ObsSceneAssign(scene) => {
Message::ObsSceneAssign(*scene) Message::AssignObsScene(*scene)
} }
MenuAction::ObsStartStream => Message::ObsStartStream, MenuAction::ObsStartStream => Message::AssignSlideAction(
MenuAction::ObsStopStream => Message::ObsStopStream, slide_actions::Action::Obs {
action: ObsAction::StartStream,
},
),
MenuAction::ObsStopStream => Message::AssignSlideAction(
slide_actions::Action::Obs {
action: ObsAction::StopStream,
},
),
MenuAction::ObsStartRecord => todo!(), MenuAction::ObsStartRecord => todo!(),
MenuAction::ObsStopRecord => todo!(), MenuAction::ObsStopRecord => todo!(),
} }
@ -337,7 +345,7 @@ impl Presenter {
debug!(?scenes, "updating obs scenes"); debug!(?scenes, "updating obs scenes");
self.obs_scenes = Some(scenes); self.obs_scenes = Some(scenes);
} }
Message::ObsSceneAssign(scene_index) => { Message::AssignObsScene(scene_index) => {
let Some(scenes) = &self.obs_scenes else { let Some(scenes) = &self.obs_scenes else {
return Action::None; return Action::None;
}; };
@ -404,8 +412,27 @@ impl Presenter {
self.slide_action_map = Some(map); self.slide_action_map = Some(map);
} }
} }
Message::ObsStartStream => todo!(), Message::AssignSlideAction(action) => {
Message::ObsStopStream => todo!(), if let Some(map) = self.slide_action_map.as_mut() {
if let Some(actions) =
map.get_mut(&self.context_menu_id.unwrap())
{
actions.push(action)
} else {
map.insert(
self.context_menu_id.unwrap(),
vec![action],
);
}
} else {
let mut map = HashMap::new();
map.insert(
self.context_menu_id.unwrap(),
vec![action],
);
self.slide_action_map = Some(map);
}
}
Message::ActivateSlide(item_index, slide_index) => { Message::ActivateSlide(item_index, slide_index) => {
debug!(slide_index, item_index); debug!(slide_index, item_index);
if let Some(slide) = self if let Some(slide) = self
@ -743,11 +770,11 @@ impl Presenter {
))) )))
}) })
.on_exit(Message::HoveredSlide(None)) .on_exit(Message::HoveredSlide(None))
.on_press(Message::ClickSlide( .on_release(Message::ClickSlide(
item_index, item_index,
slide_index, slide_index,
)) ))
.on_right_press(Message::RightClickSlide( .on_right_release(Message::RightClickSlide(
item_index, item_index,
slide_index, slide_index,
)); ));
@ -771,7 +798,7 @@ impl Presenter {
items.push(divider.into()); items.push(divider.into());
}, },
); );
let row = let scrollable =
scrollable(container(Row::from_vec(items)).style(|t| { scrollable(container(Row::from_vec(items)).style(|t| {
let style = container::Style::default(); let style = container::Style::default();
style.border(Border::default().width(2)) style.border(Border::default().width(2))
@ -780,8 +807,7 @@ impl Presenter {
.height(Length::Fill) .height(Length::Fill)
.width(Length::Fill) .width(Length::Fill)
.id(self.scroll_id.clone()); .id(self.scroll_id.clone());
let context_menu = self.context_menu(row.into()); self.context_menu(scrollable.into())
context_menu.into()
} }
fn context_menu<'a>( fn context_menu<'a>(
@ -789,9 +815,6 @@ impl Presenter {
items: Element<'a, Message>, items: Element<'a, Message>,
) -> Element<'a, Message> { ) -> Element<'a, Message> {
if self.context_menu_id.is_some() { if self.context_menu_id.is_some() {
let before_icon =
icon::from_path("./res/split-above.svg".into())
.symbolic(true);
let mut scenes = vec![]; let mut scenes = vec![];
if let Some(obs_scenes) = &self.obs_scenes { if let Some(obs_scenes) = &self.obs_scenes {
for scene in obs_scenes { for scene in obs_scenes {
@ -805,9 +828,14 @@ impl Presenter {
} }
let menu_items = vec![ let menu_items = vec![
menu::Item::Button( menu::Item::Button(
"Test Scene".to_string(), "Start Stream".to_string(),
None, None,
MenuAction::ObsSceneAssign(0), MenuAction::ObsStartStream,
),
menu::Item::Button(
"Stop Stream".to_string(),
None,
MenuAction::ObsStopStream,
), ),
menu::Item::Folder("Obs Scene".to_string(), scenes), menu::Item::Folder("Obs Scene".to_string(), scenes),
]; ];