better draggable code
Some checks are pending
/ test (push) Waiting to run

This commit is contained in:
Chris Cochrun 2025-09-23 12:57:12 -05:00
parent 1f3c70279a
commit e2b72c4ef6
2 changed files with 42 additions and 60 deletions

View file

@ -48,6 +48,7 @@ use ui::EditorMode;
use crate::core::kinds::ServiceItemKind; use crate::core::kinds::ServiceItemKind;
use crate::ui::text_svg::{self}; use crate::ui::text_svg::{self};
use crate::ui::widgets::draggable;
pub mod core; pub mod core;
pub mod lisp; pub mod lisp;
@ -112,6 +113,7 @@ struct App {
presenter: Presenter, presenter: Presenter,
windows: Vec<window::Id>, windows: Vec<window::Id>,
service: Vec<ServiceItem>, service: Vec<ServiceItem>,
selected_items: Vec<usize>,
current_item: (usize, usize), current_item: (usize, usize),
hovered_item: Option<usize>, hovered_item: Option<usize>,
presentation_open: bool, presentation_open: bool,
@ -146,6 +148,8 @@ enum Message {
None, None,
EditorToggle(bool), EditorToggle(bool),
ChangeServiceItem(usize), ChangeServiceItem(usize),
SelectServiceItem(usize),
AddSelectServiceItem(usize),
HoveredServiceItem(Option<usize>), HoveredServiceItem(Option<usize>),
AddServiceItem(usize, ServiceItem), AddServiceItem(usize, ServiceItem),
AddServiceItemDrop(usize), AddServiceItemDrop(usize),
@ -302,6 +306,7 @@ impl cosmic::Application for App {
core, core,
nav_model, nav_model,
service: items, service: items,
selected_items: vec![],
file: PathBuf::default(), file: PathBuf::default(),
windows, windows,
presentation_open: false, presentation_open: false,
@ -1007,6 +1012,14 @@ impl cosmic::Application for App {
self.hovered_item = index; self.hovered_item = index;
Task::none() Task::none()
} }
Message::SelectServiceItem(index) => {
self.selected_items = vec![index];
Task::none()
}
Message::AddSelectServiceItem(index) => {
self.selected_items.push(index);
Task::none()
}
Message::ChangeServiceItem(index) => { Message::ChangeServiceItem(index) => {
if let Some((index, item)) = self if let Some((index, item)) = self
.service .service
@ -1448,7 +1461,10 @@ where
|hovered_index| { |hovered_index| {
index == hovered_index index == hovered_index
}, },
) { ) || self
.selected_items
.contains(&index)
{
t.cosmic().button.hover.into() t.cosmic().button.hover.into()
} else { } else {
t.cosmic().button.base.into() t.cosmic().button.base.into()
@ -1464,35 +1480,11 @@ where
index, index,
))) )))
.on_exit(Message::HoveredServiceItem(None)) .on_exit(Message::HoveredServiceItem(None))
.on_double_press(Message::None) .on_double_press(Message::ChangeServiceItem(
index,
))
.on_drag(Message::None) .on_drag(Message::None)
.on_press(Message::ChangeServiceItem(index)); .on_release(Message::SelectServiceItem(index));
// let button = button::standard(item.title.clone())
// .leading_icon({
// match item.kind {
// core::kinds::ServiceItemKind::Song(_) => {
// icon::from_name("folder-music-symbolic")
// },
// core::kinds::ServiceItemKind::Video(_) => {
// icon::from_name("folder-videos-symbolic")
// },
// core::kinds::ServiceItemKind::Image(_) => {
// icon::from_name("folder-pictures-symbolic")
// },
// core::kinds::ServiceItemKind::Presentation(_) => {
// icon::from_name("x-office-presentation-symbolic")
// },
// core::kinds::ServiceItemKind::Content(_) => {
// icon::from_name("x-office-presentation-symbolic")
// },
// }
// })
// // .icon_size(cosmic::theme::spacing().space_l)
// .class(cosmic::theme::style::Button::HeaderBar)
// // .spacing(cosmic::theme::spacing().space_l)
// .height(cosmic::theme::spacing().space_xl)
// .width(Length::Fill)
// .on_press(Message::ChangeServiceItem(index));
let tooltip = tooltip( let tooltip = tooltip(
mouse_area, mouse_area,
text::body(item.kind.to_string()), text::body(item.kind.to_string()),
@ -1501,10 +1493,7 @@ where
.gap(cosmic::theme::spacing().space_xs); .gap(cosmic::theme::spacing().space_xs);
dnd_destination( dnd_destination(
tooltip, tooltip,
vec![ vec!["application/service-item".into()],
"application/service-item".into(),
"video/mp4".into(),
],
) )
.data_received_for::<ServiceItem>(move |item| { .data_received_for::<ServiceItem>(move |item| {
if let Some(item) = item { if let Some(item) = item {
@ -1531,15 +1520,26 @@ where
.center() .center()
.width(Length::Fill), .width(Length::Fill),
iced::widget::horizontal_rule(1), iced::widget::horizontal_rule(1),
ui::widgets::draggable::column::column(list).spacing(10).on_drag(|event| { draggable::column::column(list).spacing(10).on_drag(
match event { |event| {
ui::widgets::draggable::DragEvent::Picked { index } => Message::None, match event {
ui::widgets::draggable::DragEvent::Dropped { index, target_index, drop_position } => Message::ReorderService(index, target_index), draggable::DragEvent::Picked { .. } => {
ui::widgets::draggable::DragEvent::Canceled { index } => Message::None, Message::None
}
draggable::DragEvent::Dropped {
index,
target_index,
..
} => Message::ReorderService(
index,
target_index,
),
draggable::DragEvent::Canceled { .. } => {
Message::None
}
}
} }
}), ),
// column(list).spacing(10),
// service::service(&self.service),
dnd_destination( dnd_destination(
vertical_space().width(Length::Fill), vertical_space().width(Length::Fill),
vec!["application/service-item".into()] vec!["application/service-item".into()]
@ -1570,22 +1570,3 @@ where
container.center(Length::FillPortion(2)).into() container.center(Length::FillPortion(2)).into()
} }
} }
#[cfg(test)]
mod test {
fn test_slide() -> String {
let slide = r#"(slide (image :source "./somehting.jpg" :fill cover
(text "Something cooler" :font-size 50)))"#;
String::from(slide)
}
// #[test]
// fn test_lisp() {
// let slide = test_slide();
// if let Ok(data) = lexpr::parse::from_str_elisp(slide.as_str()) {
// assert_eq!(slide, data)
// } else {
// assert!(false)
// }
// }
}

View file

@ -2,6 +2,7 @@
* TODO [#A] Add removal and reordering of service_items * TODO [#A] Add removal and reordering of service_items
Reordering is finished
* TODO Add OBS integration * TODO Add OBS integration
This will be based on each slide having the ability to activate an OBS scene when it is active. This will be based on each slide having the ability to activate an OBS scene when it is active.
* TODO Move text_generation function to be asynchronous so that UI doesn't lock up during song editing. * TODO Move text_generation function to be asynchronous so that UI doesn't lock up during song editing.