adding more song_editor pieces

This commit is contained in:
Chris Cochrun 2025-02-21 23:17:51 -06:00
parent f13d021b22
commit ab88791d80
3 changed files with 145 additions and 126 deletions

View file

@ -417,49 +417,7 @@ impl cosmic::Application for App {
fn update(&mut self, message: Message) -> Task<Message> { fn update(&mut self, message: Message) -> Task<Message> {
match message { match message {
Message::Key(key, modifiers) => { Message::Key(key, modifiers) => {
debug!(?key, ?modifiers); self.process_key_press(key, modifiers)
match (key, modifiers) {
(
Key::Named(
iced::keyboard::key::Named::ArrowRight,
),
_,
) => self.update(Message::Present(
presenter::Message::NextSlide,
)),
(
Key::Named(
iced::keyboard::key::Named::ArrowLeft,
),
_,
) => self.update(Message::Present(
presenter::Message::PrevSlide,
)),
(
Key::Named(iced::keyboard::key::Named::Space),
_,
) => self.update(Message::Present(
presenter::Message::NextSlide,
)),
(Key::Character(k), _)
if k == *"j" || k == *"l" =>
{
self.update(Message::Present(
presenter::Message::NextSlide,
))
}
(Key::Character(k), _)
if k == *"k" || k == *"h" =>
{
self.update(Message::Present(
presenter::Message::PrevSlide,
))
}
(Key::Character(k), _) if k == *"q" => {
self.update(Message::Quit)
}
_ => Task::none(),
}
} }
Message::SongEditor(message) => { Message::SongEditor(message) => {
self.song_editor.update(message).map(|m| { self.song_editor.update(message).map(|m| {
@ -654,13 +612,9 @@ impl cosmic::Application for App {
] ]
.spacing(3); .spacing(3);
let mut drag_item = None;
let library = let library =
Container::new(if let Some(library) = &self.library { Container::new(if let Some(library) = &self.library {
let (view, item) = library.view(); library.view().map(|m| Message::Library(m))
drag_item = item;
view.map(|m| Message::Library(m))
} else { } else {
Space::new(0, 0).into() Space::new(0, 0).into()
}) })
@ -714,7 +668,7 @@ impl cosmic::Application for App {
.center_y(130) .center_y(130)
]; ];
if let Some(editor) = &self.editor_mode { if let Some(_editor) = &self.editor_mode {
Element::from(song_editor) Element::from(song_editor)
} else { } else {
Element::from(column) Element::from(column)
@ -767,6 +721,45 @@ where
cosmic::app::Message::App(Message::AddLibrary(x)) cosmic::app::Message::App(Message::AddLibrary(x))
}) })
} }
fn process_key_press(
&mut self,
key: Key,
modifiers: Modifiers,
) -> Task<Message> {
debug!(?key, ?modifiers);
match (key, modifiers) {
(
Key::Named(iced::keyboard::key::Named::ArrowRight),
_,
) => self.update(Message::Present(
presenter::Message::NextSlide,
)),
(
Key::Named(iced::keyboard::key::Named::ArrowLeft),
_,
) => self.update(Message::Present(
presenter::Message::PrevSlide,
)),
(Key::Named(iced::keyboard::key::Named::Space), _) => {
self.update(Message::Present(
presenter::Message::NextSlide,
))
}
(Key::Character(k), _) if k == *"j" || k == *"l" => self
.update(Message::Present(
presenter::Message::NextSlide,
)),
(Key::Character(k), _) if k == *"k" || k == *"h" => self
.update(Message::Present(
presenter::Message::PrevSlide,
)),
(Key::Character(k), _) if k == *"q" => {
self.update(Message::Quit)
}
_ => Task::none(),
}
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,10 +1,10 @@
use cosmic::{ use cosmic::{
iced::{alignment::Vertical, Background, Border, Length}, iced::{alignment::Vertical, Background, Border, Length},
iced_core::widget::tree::State, iced_core::widget::tree,
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,
row, scrollable, text, Container, DndSource, Space, row, scrollable, text, Container, DndSource, Space, Widget,
}, },
Element, Task, Element, Task,
}; };
@ -31,7 +31,6 @@ pub(crate) struct Library {
selected_item: Option<(LibraryKind, i32)>, selected_item: Option<(LibraryKind, i32)>,
hovered_item: Option<(LibraryKind, i32)>, hovered_item: Option<(LibraryKind, i32)>,
dragged_item: Option<(LibraryKind, i32)>, dragged_item: Option<(LibraryKind, i32)>,
dragged_item_pos: Option<(usize, usize)>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -43,7 +42,6 @@ pub(crate) enum Message {
OpenLibrary(Option<LibraryKind>), OpenLibrary(Option<LibraryKind>),
HoverItem(Option<(LibraryKind, i32)>), HoverItem(Option<(LibraryKind, i32)>),
SelectItem(Option<(LibraryKind, i32)>), SelectItem(Option<(LibraryKind, i32)>),
DragItem(Option<(LibraryKind, i32)>),
None, None,
} }
@ -63,7 +61,6 @@ impl Library {
selected_item: None, selected_item: None,
hovered_item: None, hovered_item: None,
dragged_item: None, dragged_item: None,
dragged_item_pos: None,
} }
} }
@ -89,24 +86,14 @@ impl Library {
self.selected_item = item; self.selected_item = item;
Task::none() Task::none()
} }
Message::DragItem(item) => {
self.dragged_item = item;
debug!(?self.dragged_item);
Task::none()
}
} }
} }
pub fn view( pub fn view(&self) -> Element<Message> {
&self, let song_library = self.library_item(&self.song_library);
) -> (Element<Message>, Option<Element<Message>>) { let image_library = self.library_item(&self.image_library);
let (song_library, song_dragged) = let video_library = self.library_item(&self.video_library);
self.library_item(&self.song_library); let presentation_library =
let (image_library, image_dragged) =
self.library_item(&self.image_library);
let (video_library, video_dragged) =
self.library_item(&self.video_library);
let (presentation_library, presentation_dragged) =
self.library_item(&self.presentation_library); self.library_item(&self.presentation_library);
let column = column![ let column = column![
song_library, song_library,
@ -114,25 +101,13 @@ impl Library {
video_library, video_library,
presentation_library, presentation_library,
]; ];
let dragged_vector = vec![ column.height(Length::Fill).spacing(5).into()
song_dragged,
image_dragged,
video_dragged,
presentation_dragged,
];
let dragged = dragged_vector
.into_iter()
.filter(|x| x.is_some())
.next()
.unwrap_or(None);
(column.height(Length::Fill).spacing(5).into(), dragged)
} }
pub fn library_item<'a, T>( pub fn library_item<'a, T>(
&'a self, &'a self,
model: &'a Model<T>, model: &'a Model<T>,
) -> (Element<'a, Message>, Option<Element<'a, Message>>) ) -> Element<'a, Message>
where where
T: Content, T: Content,
{ {
@ -205,7 +180,6 @@ impl Library {
}) })
.on_enter(Message::HoverLibrary(Some(model.kind))) .on_enter(Message::HoverLibrary(Some(model.kind)))
.on_exit(Message::HoverLibrary(None)); .on_exit(Message::HoverLibrary(None));
let mut dragged_item = None;
let lib_container = let lib_container =
if self.library_open == Some(model.kind) { if self.library_open == Some(model.kind) {
let items = scrollable( let items = scrollable(
@ -213,33 +187,35 @@ impl Library {
model.items.iter().enumerate().map( model.items.iter().enumerate().map(
|(index, item)| { |(index, item)| {
let service_item = item.to_service_item(); let service_item = item.to_service_item();
let visual_item = self
.single_item(index, item, model)
.map(|_| Message::None);
DndSource::<Message, ServiceItem>::new( DndSource::<Message, ServiceItem>::new(
mouse_area( mouse_area(visual_item)
self.single_item( .on_enter(Message::HoverItem(
index, item, model, Some((
), model.kind,
) index as i32,
.on_enter(Message::HoverItem(Some(( )),
model.kind, ))
index as i32, .on_exit(Message::HoverItem(None))
)))) .on_press(Message::SelectItem(
.on_exit(Message::HoverItem(None)) Some((
.on_press(Message::SelectItem(Some( model.kind,
(model.kind, index as i32), index as i32,
))), )),
)),
) )
// .drag_icon(move |i| {
// let drag_item =
// self.single_item(index, item, model);
// let state =
// drag_item.as_widget().state();
// (drag_item, state, i)
// })
.drag_content(move || { .drag_content(move || {
service_item.to_owned() service_item.to_owned()
}) })
.on_start(Some(Message::DragItem(Some(
(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()
}, },
) )
@ -259,7 +235,7 @@ impl Library {
} else { } else {
Container::new(Space::new(0, 0)) Container::new(Space::new(0, 0))
}; };
(column![button, lib_container].into(), dragged_item) column![button, lib_container].into()
} }
fn single_item<'a, T>( fn single_item<'a, T>(
@ -267,7 +243,7 @@ impl Library {
index: usize, index: usize,
item: &'a T, item: &'a T,
model: &'a Model<T>, model: &'a Model<T>,
) -> Element<'a, Message> ) -> Element<'a, ()>
where where
T: Content, T: Content,
{ {

View file

@ -1,29 +1,38 @@
use cosmic::{ use cosmic::{
iced_widget::{column, row}, iced::Length,
widget::{dropdown, text, text_input}, iced_widget::row,
widget::{
column, combo_box, container, dropdown, text_editor,
text_input, vertical_space,
},
Element, Task, Element, Task,
}; };
use tracing::debug; use tracing::debug;
use crate::core::songs::Song; use crate::core::songs::Song;
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct SongEditor { pub struct SongEditor {
song: Option<Song>, song: Option<Song>,
title: String, title: String,
fonts: Vec<String>, fonts: combo_box::State<String>,
font_sizes: Vec<String>, font_sizes: Vec<String>,
font: String, font: String,
font_size: usize, font_size: usize,
verse_order: String,
lyrics: text_editor::Content,
editing: bool,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
ChangeSong(Song), ChangeSong(Song),
UpdateSong(Song), UpdateSong(Song),
ChangeFont(usize), ChangeFont(String),
ChangeFontSize(usize), ChangeFontSize(usize),
ChangeTitle(String), ChangeTitle(String),
ChangeVerseOrder(String),
ChangeLyrics(text_editor::Action),
} }
impl SongEditor { impl SongEditor {
@ -41,22 +50,28 @@ impl SongEditor {
]; ];
Self { Self {
song: None, song: None,
fonts, fonts: combo_box::State::new(fonts),
title: String::from("Death was Arrested"), title: String::from("Death was Arrested"),
font: String::from("Quicksand"), font: String::from("Quicksand"),
font_size: 16, font_size: 16,
font_sizes, font_sizes,
verse_order: String::from("Death was Arrested"),
lyrics: text_editor::Content::new(),
editing: false,
} }
} }
pub fn update(&mut self, message: Message) -> Task<Message> { pub fn update(&mut self, message: Message) -> Task<Message> {
match message { match message {
Message::ChangeSong(song) => todo!(), Message::ChangeSong(song) => {
Message::UpdateSong(song) => todo!(), self.song = Some(song);
Task::none()
}
Message::UpdateSong(song) => {
self.song = Some(song);
Task::none()
}
Message::ChangeFont(font) => { Message::ChangeFont(font) => {
if let Some(font) = self.fonts.get(font) { self.font = font;
debug!(font);
self.font = font.to_owned();
}
Task::none() Task::none()
} }
Message::ChangeFontSize(size) => { Message::ChangeFontSize(size) => {
@ -72,19 +87,30 @@ impl SongEditor {
self.title = title; self.title = title;
Task::none() Task::none()
} }
Message::ChangeVerseOrder(verse_order) => {
self.verse_order = verse_order;
Task::none()
}
Message::ChangeLyrics(action) => {
self.lyrics.perform(action);
Task::none()
}
} }
} }
pub fn view(&self) -> Element<Message> { pub fn view(&self) -> Element<Message> {
let selected_font = let selected_font = &self.font;
self.fonts.iter().position(|f| *f == self.font);
let selected_font_size = self let selected_font_size = self
.font_sizes .font_sizes
.iter() .iter()
.position(|s| *s == self.font_size.to_string()); .position(|s| *s == self.font_size.to_string());
let font_selector = let font_selector = combo_box(
dropdown(&self.fonts, selected_font, Message::ChangeFont) &self.fonts,
.width(200); "Font",
Some(selected_font),
Message::ChangeFont,
)
.width(200);
let font_size = dropdown( let font_size = dropdown(
&self.font_sizes, &self.font_sizes,
selected_font_size, selected_font_size,
@ -93,8 +119,32 @@ impl SongEditor {
let title_input = text_input("song", &self.title) let title_input = text_input("song", &self.title)
.on_input(Message::ChangeTitle) .on_input(Message::ChangeTitle)
.label("Song Title"); .label("Song Title");
let verse_input = text_input(
"Verse
order",
&self.verse_order,
)
.label("Verse Order")
.on_input(Message::ChangeVerseOrder);
let lyric_input = text_editor(&self.lyrics)
.on_action(Message::ChangeLyrics);
let slide_preview =
container(vertical_space()).width(Length::FillPortion(2));
let toolbar = row![font_selector, font_size]; let toolbar = row![font_selector, font_size];
let column = column![toolbar, title_input]; let left_column = column::with_children(vec![
title_input.into(),
verse_input.into(),
lyric_input.into(),
])
.spacing(25)
.width(Length::FillPortion(2));
let column = column::with_children(vec![
toolbar.into(),
row![left_column, slide_preview].into(),
]);
column.into() column.into()
} }
} }