diff --git a/Cargo.lock b/Cargo.lock index 72fd843..bc132e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,6 +489,7 @@ version = "0.1.0" dependencies = [ "exoquant", "iced", + "iced_native", "image", ] diff --git a/Cargo.toml b/Cargo.toml index fcb3b3b..72271ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ image = "0.23.14" # Display windows & graphics iced = "0.3.0" +iced_native = "0.4.0" diff --git a/src/app/lyrics.rs b/src/app/lyrics.rs index 9de5669..334515f 100644 --- a/src/app/lyrics.rs +++ b/src/app/lyrics.rs @@ -23,25 +23,67 @@ impl Lyrics { } } + pub fn insert_text(&mut self, text: String) { + + let mut pieces = text.trim_end() + .split('\n') + .map(str::trim); + + let (line_no, current_line) = self.current_line_mut(); + + current_line.deselect(); + current_line.value.push_str(pieces.next().unwrap()); + + let pieces = pieces + .collect::>() + .into_iter() + .map(str::to_owned) + .map(Lyric::new_with_value); + let n_pieces = pieces.size_hint().0; + + self.lines.splice((line_no + 1)..(line_no + 1), pieces); + + self.lines[line_no + n_pieces].select(); + } + pub fn update_line(&mut self, new_content: String, line_no: usize) { - self.lines[line_no].set_content(new_content); + self.lines[line_no].value = new_content; } pub fn advance_line(&mut self, current_line: usize) { let new_line = current_line + 1; - if new_line == self.lines.len() { - self.lines.push(Lyric::new()) - } + let line = if new_line == self.lines.len() { + self.insert_line(new_line, None) + } else { + self.lines.get_mut(new_line) + .expect("Unexpected .advance_line with index beyond # of lines") + }; + + line.select(); - self.lines.get_mut(new_line) - .expect("Unexpected .advance_line with index beyond # of lines") - .select(); self.lines.get_mut(current_line) .unwrap() .deselect(); } + pub fn insert_line(&mut self, index: usize, content: Option) -> &mut Lyric { + self.lines.insert(index, match content { + Some(content) => Lyric::new_with_value(content), + None => Lyric::new(), + }); + self.lines.get_mut(index).unwrap() + } + + pub fn current_line_mut(&mut self) -> (usize, &mut Lyric) { + self.lines + .iter_mut() + .enumerate() + .filter(|(_, l)| l.is_selected()) + .next() + .expect("no line currently selected") + } + pub fn view(&mut self, theme: Theme) -> Element { let is_sole_line = self.lines.len() == 1; self.lines.iter_mut() @@ -57,14 +99,18 @@ impl Lyrics { #[derive(Clone, Debug)] pub struct Lyric { state: text_input::State, - value: String, + pub value: String, } impl Lyric { pub fn new() -> Self { + Self::new_with_value(String::with_capacity(70)) + } + + pub fn new_with_value(val: String) -> Self { Lyric { state: text_input::State::new(), - value: String::with_capacity(70), + value: val, } } @@ -86,20 +132,20 @@ impl Lyric { ) .style(theme) .size(size) - .width(Length::Units(300)) + .width(Length::Units(350)) .on_submit(Message::LineAdvanced(line_no)) .into() } - pub fn set_content(&mut self, content: String) { - self.value = content; - } - pub fn select(&mut self) { self.state.focus(); self.state.move_cursor_to_end(); } + pub fn is_selected(&self) -> bool { + self.state.is_focused() + } + pub fn deselect(&mut self) { self.state.unfocus(); } diff --git a/src/app/mod.rs b/src/app/mod.rs index 345ce43..da4d7f1 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,9 +1,16 @@ +use iced::Subscription; +use iced::Clipboard; +use iced::Command; +use iced::Application; use iced::Container; use iced::Row; use iced::Element; -use iced::Sandbox; use iced::Length; use iced::Align; +use iced::executor; +use iced_native::subscription; +use iced_native::keyboard; +use iced_native::event::Event; mod lyrics; mod styles; @@ -23,31 +30,47 @@ pub enum Message { new_value: String, }, LineAdvanced(usize), + PasteSent, } -impl Sandbox for DelyriumApp { +impl Application for DelyriumApp { type Message = Message; + type Executor = executor::Default; + type Flags = (); - fn new() -> Self { - DelyriumApp { - lyrics_component: lyrics::Lyrics::new(), - theme: Theme::default(), - } + fn new(_: Self::Flags) -> (Self, Command) { + ( + DelyriumApp { + lyrics_component: lyrics::Lyrics::new(), + theme: Theme::default(), + }, + Command::none(), + ) } fn title(&self) -> String { String::from("Delyrium") } - fn update(&mut self, message: Message) { + fn update(&mut self, message: Message, clipboard: &mut Clipboard) -> Command{ match message { Message::LyricChanged { line_no, new_value } => { self.lyrics_component.update_line(new_value, line_no); }, Message::LineAdvanced(current_line) => { self.lyrics_component.advance_line(current_line); + }, + Message::PasteSent => { + let clip_text = clipboard.read().unwrap_or(String::new()); + let clip_pasted_len = clip_text.chars() + .filter(|c| *c != '\r' && *c != '\n') + .count(); + let line = self.lyrics_component.current_line_mut().1; + line.value.truncate(line.value.len() - clip_pasted_len); + self.lyrics_component.insert_text(clip_text); } } + Command::none() } fn view(&mut self) -> Element { @@ -60,4 +83,23 @@ impl Sandbox for DelyriumApp { .height(Length::Fill) .into() } + + fn subscription(&self) -> Subscription { + subscription::events_with(|event, _| { + match event { + Event::Keyboard(keyboard::Event::KeyPressed {key_code, modifiers}) => { + match (key_code, modifiers) { + ( + keyboard::KeyCode::V, + keyboard::Modifiers { control, .. } + ) if control == true => { + Some(Message::PasteSent) + } + _ => { None } + } + } + _ => { None } + } + }) + } } diff --git a/src/main.rs b/src/main.rs index df0558f..ebbf474 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use iced::Sandbox; +use iced::Application; use iced::settings::Settings; mod palette;