Drag and Drop works ok now.
The main functionality works but only in cosmic desktop. So there are some issues that need to be worked out yet in regards to libcosmic.
This commit is contained in:
parent
614630bea8
commit
a36a1d59c6
883
Cargo.lock
generated
883
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ use super::{
|
||||||
model::{get_db, LibraryKind, Model},
|
model::{get_db, LibraryKind, Model},
|
||||||
service_items::ServiceTrait,
|
service_items::ServiceTrait,
|
||||||
};
|
};
|
||||||
use crisp::types::{Keyword, Value};
|
use crisp::types::{Keyword, Symbol, Value};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{query_as, SqliteConnection};
|
use sqlx::{query_as, SqliteConnection};
|
||||||
|
@ -22,6 +22,12 @@ pub struct Image {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Image> for Value {
|
||||||
|
fn from(value: &Image) -> Self {
|
||||||
|
Self::List(vec![Self::Symbol(Symbol("image".into()))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Content for Image {
|
impl Content for Image {
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
self.title.clone()
|
self.title.clone()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crisp::types::{Keyword, Value};
|
use crisp::types::{Keyword, Symbol, Value};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
|
@ -36,6 +36,12 @@ pub struct Presentation {
|
||||||
pub kind: PresKind,
|
pub kind: PresKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Presentation> for Value {
|
||||||
|
fn from(value: &Presentation) -> Self {
|
||||||
|
Self::List(vec![Self::Symbol(Symbol("presentation".into()))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Content for Presentation {
|
impl Content for Presentation {
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
self.title.clone()
|
self.title.clone()
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl AllowedMimeTypes for ServiceItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMimeTypes for ServiceItem {
|
impl AsMimeTypes for ServiceItem {
|
||||||
fn available(&self) -> std::borrow::Cow<'static, [String]> {
|
fn available(&self) -> Cow<'static, [String]> {
|
||||||
debug!(?self);
|
debug!(?self);
|
||||||
Cow::from(vec!["application/service-item".to_string()])
|
Cow::from(vec!["application/service-item".to_string()])
|
||||||
}
|
}
|
||||||
|
@ -67,11 +67,13 @@ impl AsMimeTypes for ServiceItem {
|
||||||
impl From<&ServiceItem> for Value {
|
impl From<&ServiceItem> for Value {
|
||||||
fn from(value: &ServiceItem) -> Self {
|
fn from(value: &ServiceItem) -> Self {
|
||||||
match &value.kind {
|
match &value.kind {
|
||||||
ServiceItemKind::Song(song) => todo!(),
|
ServiceItemKind::Song(song) => Value::from(song),
|
||||||
ServiceItemKind::Video(video) => todo!(),
|
ServiceItemKind::Video(video) => Value::from(video),
|
||||||
ServiceItemKind::Image(image) => todo!(),
|
ServiceItemKind::Image(image) => Value::from(image),
|
||||||
ServiceItemKind::Presentation(presentation) => todo!(),
|
ServiceItemKind::Presentation(presentation) => {
|
||||||
ServiceItemKind::Content(slide) => todo!(),
|
Value::from(presentation)
|
||||||
|
}
|
||||||
|
ServiceItemKind::Content(slide) => Value::from(slide),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,6 +194,12 @@ pub struct Slide {
|
||||||
video_end_time: f32,
|
video_end_time: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Slide> for Value {
|
||||||
|
fn from(value: &Slide) -> Self {
|
||||||
|
Self::List(vec![Self::Symbol(Symbol("slide".into()))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Slide {
|
impl Slide {
|
||||||
pub fn background(&self) -> &Background {
|
pub fn background(&self) -> &Background {
|
||||||
&self.background
|
&self.background
|
||||||
|
|
|
@ -36,6 +36,12 @@ pub struct Song {
|
||||||
pub font_size: Option<i32>,
|
pub font_size: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Song> for Value {
|
||||||
|
fn from(value: &Song) -> Self {
|
||||||
|
Self::List(vec![Self::Symbol(Symbol("song".into()))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Content for Song {
|
impl Content for Song {
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
self.title.clone()
|
self.title.clone()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::{
|
||||||
slide::Slide,
|
slide::Slide,
|
||||||
};
|
};
|
||||||
use cosmic::iced::Executor;
|
use cosmic::iced::Executor;
|
||||||
use crisp::types::{Keyword, Value};
|
use crisp::types::{Keyword, Symbol, Value};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{query_as, SqliteConnection};
|
use sqlx::{query_as, SqliteConnection};
|
||||||
|
@ -27,6 +27,12 @@ pub struct Video {
|
||||||
pub looping: bool,
|
pub looping: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Video> for Value {
|
||||||
|
fn from(value: &Video) -> Self {
|
||||||
|
Self::List(vec![Self::Symbol(Symbol("video".into()))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Content for Video {
|
impl Content for Video {
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
self.title.clone()
|
self.title.clone()
|
||||||
|
|
37
src/main.rs
37
src/main.rs
|
@ -15,7 +15,8 @@ use cosmic::widget::nav_bar::nav_bar_style;
|
||||||
use cosmic::widget::segmented_button::Entity;
|
use cosmic::widget::segmented_button::Entity;
|
||||||
use cosmic::widget::tooltip::Position as TPosition;
|
use cosmic::widget::tooltip::Position as TPosition;
|
||||||
use cosmic::widget::{
|
use cosmic::widget::{
|
||||||
button, nav_bar, text, tooltip, DndSource, Id, Space,
|
button, nav_bar, text, tooltip, DndDestination, DndSource, Id,
|
||||||
|
Space,
|
||||||
};
|
};
|
||||||
use cosmic::widget::{icon, slider};
|
use cosmic::widget::{icon, slider};
|
||||||
use cosmic::{executor, Application, ApplicationExt, Element};
|
use cosmic::{executor, Application, ApplicationExt, Element};
|
||||||
|
@ -28,6 +29,7 @@ use std::path::PathBuf;
|
||||||
use tracing::{debug, level_filters::LevelFilter};
|
use tracing::{debug, level_filters::LevelFilter};
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
use ui::editor::SongEditor;
|
||||||
use ui::library::{self, Library};
|
use ui::library::{self, Library};
|
||||||
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
@ -96,12 +98,14 @@ struct App {
|
||||||
library: Option<Library>,
|
library: Option<Library>,
|
||||||
library_open: bool,
|
library_open: bool,
|
||||||
library_width: f32,
|
library_width: f32,
|
||||||
|
song_editor: SongEditor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
Present(presenter::Message),
|
Present(presenter::Message),
|
||||||
Library(library::Message),
|
Library(library::Message),
|
||||||
|
SongEditor(editor::Message),
|
||||||
File(PathBuf),
|
File(PathBuf),
|
||||||
DndEnter(Entity, Vec<String>),
|
DndEnter(Entity, Vec<String>),
|
||||||
DndDrop(Entity, Option<ServiceItem>, DndAction),
|
DndDrop(Entity, Option<ServiceItem>, DndAction),
|
||||||
|
@ -165,6 +169,7 @@ impl cosmic::Application for App {
|
||||||
let presenter = Presenter::with_items(items.clone());
|
let presenter = Presenter::with_items(items.clone());
|
||||||
let slides = items.to_slides().unwrap_or_default();
|
let slides = items.to_slides().unwrap_or_default();
|
||||||
let current_slide = slides[0].clone();
|
let current_slide = slides[0].clone();
|
||||||
|
let song_editor = SongEditor::new();
|
||||||
|
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
nav_model.insert().text(item.title()).data(item.clone());
|
nav_model.insert().text(item.title()).data(item.clone());
|
||||||
|
@ -174,6 +179,7 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
presenter,
|
presenter,
|
||||||
|
song_editor,
|
||||||
core,
|
core,
|
||||||
nav_model,
|
nav_model,
|
||||||
file: PathBuf::default(),
|
file: PathBuf::default(),
|
||||||
|
@ -221,15 +227,12 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::cosmic::Message::NavBar(id),
|
cosmic::app::cosmic::Message::NavBar(id),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.on_dnd_drop(|entity, data, action| {
|
|
||||||
cosmic::app::Message::App(Message::DndDrop(
|
|
||||||
entity, data, action,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.on_dnd_enter(|entity, data| {
|
.on_dnd_enter(|entity, data| {
|
||||||
|
debug!("entered");
|
||||||
cosmic::app::Message::App(Message::DndEnter(entity, data))
|
cosmic::app::Message::App(Message::DndEnter(entity, data))
|
||||||
})
|
})
|
||||||
.on_dnd_leave(|entity| {
|
.on_dnd_leave(|entity| {
|
||||||
|
debug!("left");
|
||||||
cosmic::app::Message::App(Message::DndLeave(entity))
|
cosmic::app::Message::App(Message::DndLeave(entity))
|
||||||
})
|
})
|
||||||
.drag_id(DragId::new())
|
.drag_id(DragId::new())
|
||||||
|
@ -238,6 +241,12 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::cosmic::Message::NavBarContext(id),
|
cosmic::app::cosmic::Message::NavBarContext(id),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
.on_dnd_drop::<ServiceItem>(|entity, data, action| {
|
||||||
|
debug!("dropped");
|
||||||
|
cosmic::app::Message::App(Message::DndDrop(
|
||||||
|
entity, data, action,
|
||||||
|
))
|
||||||
|
})
|
||||||
.context_menu(None)
|
.context_menu(None)
|
||||||
.into_container()
|
.into_container()
|
||||||
// XXX both must be shrink to avoid flex layout from ignoring it
|
// XXX both must be shrink to avoid flex layout from ignoring it
|
||||||
|
@ -248,6 +257,14 @@ impl cosmic::Application for App {
|
||||||
nav = nav.max_width(280);
|
nav = nav.max_width(280);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let dnd = DndDestination::new(
|
||||||
|
// nav,
|
||||||
|
// vec!["application/service-item".to_string().into()],
|
||||||
|
// )
|
||||||
|
// .data_received_for(|item| {
|
||||||
|
// cosmic::app::Message::App(Message::DndDrop(item))
|
||||||
|
// });
|
||||||
|
|
||||||
let column = column![
|
let column = column![
|
||||||
text::heading("Service List").center().width(280),
|
text::heading("Service List").center().width(280),
|
||||||
nav
|
nav
|
||||||
|
@ -423,6 +440,9 @@ impl cosmic::Application for App {
|
||||||
_ => Task::none(),
|
_ => Task::none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::SongEditor(message) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
Message::Present(message) => {
|
Message::Present(message) => {
|
||||||
// debug!(?message);
|
// debug!(?message);
|
||||||
if self.presentation_open {
|
if self.presentation_open {
|
||||||
|
@ -523,8 +543,8 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
Message::DndDrop(entity, service_item, action) => {
|
Message::DndDrop(entity, service_item, action) => {
|
||||||
debug!(?entity);
|
debug!(?entity);
|
||||||
debug!(?service_item);
|
|
||||||
debug!(?action);
|
debug!(?action);
|
||||||
|
debug!(?service_item);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::AddLibrary(library) => {
|
Message::AddLibrary(library) => {
|
||||||
|
@ -614,6 +634,9 @@ impl cosmic::Application for App {
|
||||||
})
|
})
|
||||||
.style(nav_bar_style)
|
.style(nav_bar_style)
|
||||||
.center(Length::Fill);
|
.center(Length::Fill);
|
||||||
|
|
||||||
|
let song_editor =
|
||||||
|
self.song_editor.view().map(|m| Message::SongEditor(m));
|
||||||
// let dnd_source: DndSource<Message, _> = DndSource::with_id(
|
// let dnd_source: DndSource<Message, _> = DndSource::with_id(
|
||||||
// drag_item.expect("errors").map(|m| Message::Library(m)),
|
// drag_item.expect("errors").map(|m| Message::Library(m)),
|
||||||
// Id::new("item"),
|
// Id::new("item"),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::{alignment::Vertical, Background, Border, Length},
|
iced::{alignment::Vertical, Background, Border, Length},
|
||||||
|
iced_core::widget::tree::State,
|
||||||
iced_widget::{column, row as rowm, text as textm},
|
iced_widget::{column, row as rowm, text as textm},
|
||||||
widget::{
|
widget::{
|
||||||
container, horizontal_space, icon, mouse_area, responsive,
|
container, horizontal_space, icon, mouse_area, responsive,
|
||||||
|
@ -233,6 +234,12 @@ impl Library {
|
||||||
.on_start(Some(Message::DragItem(Some(
|
.on_start(Some(Message::DragItem(Some(
|
||||||
(model.kind, index as i32),
|
(model.kind, index as i32),
|
||||||
))))
|
))))
|
||||||
|
.on_finish(Some(Message::DragItem(Some(
|
||||||
|
(model.kind, index as i32),
|
||||||
|
))))
|
||||||
|
.on_cancel(Some(Message::DragItem(Some(
|
||||||
|
(model.kind, index as i32),
|
||||||
|
))))
|
||||||
.into()
|
.into()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
1
todo.org
1
todo.org
|
@ -5,6 +5,7 @@
|
||||||
** DONE Develop ui for libraries
|
** DONE Develop ui for libraries
|
||||||
I've got the library basic layer done, I need to develop a way to open the libraries accordion button and then show the list of items in the library
|
I've got the library basic layer done, I need to develop a way to open the libraries accordion button and then show the list of items in the library
|
||||||
** TODO Develop DnD for library items
|
** TODO Develop DnD for library items
|
||||||
|
This is limited by the fact that I need to develop this in cosmic. I am honestly thinking that I'll need to build my own drag and drop system or at least work with system76 to fix their dnd system on other systems.
|
||||||
|
|
||||||
* TODO Build editors for each possible item
|
* TODO Build editors for each possible item
|
||||||
** TODO Develop ui for editors
|
** TODO Develop ui for editors
|
||||||
|
|
Loading…
Reference in a new issue