diff --git a/src/main.rs b/src/main.rs index 9b24b53..c944f06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![feature(iter_map_windows)] use iced::keyboard::key::Named; use iced::keyboard::{Key, Modifiers}; -use iced::{event, task, Event, Subscription}; +use iced::{event, Event, Subscription}; use iced::widget::scrollable; use iced::{ Element, Length, Task, Theme, clipboard, color, @@ -12,6 +12,7 @@ use iced::{ }, }; +use std::sync::Arc; use std::{env, fs, path::PathBuf}; use texts::*; @@ -32,7 +33,7 @@ fn main() -> iced::Result { if let Some(second_query) = arg.get(2) { if let Ok(contents) = fs::read_to_string(&format!("{BIBLE_DIRECTORY}/EnglishNASBBible.xml")) { if let Ok(bible) = quick_xml::de::from_str::(&contents) { - if let Some(f) = bible::get( + if let Ok(f) = bible::get( query, second_query, vec![&bible], @@ -70,10 +71,8 @@ enum Message { QuickSearch(usize, String, usize), AddColRight, DeleteColumn(usize), - ErrorSelectingBible(usize), + SetErrorMessage(usize, String), RecievedEvent(Event), - ColSelected(usize), - ColUnselected, } struct ColState { @@ -106,46 +105,11 @@ impl Default for ColState { } } -#[derive(PartialEq, Eq)] -enum SelectedInputBox { - Bible, - VerseSearch, - WordSearch, -} -impl SelectedInputBox { - fn in_order() -> Vec { - vec![ - SelectedInputBox::Bible, - SelectedInputBox::VerseSearch, - SelectedInputBox::WordSearch - ] - } - fn next(current: &Option) -> Self { - if let Some(input) = current { - if let Some(found) = Self::in_order().into_iter().find(|a| a==input) { - return found - } - } - // I don't see why this would panic - Self::in_order().into_iter().next().unwrap() - } - fn as_id_prefix(&self) -> &str { - // magic values that relate to id() as setup in the GUI - match self { - SelectedInputBox::Bible => "", - SelectedInputBox::VerseSearch => "verse-", - SelectedInputBox::WordSearch => "word-", - } - } -} - struct State { files: combo_box::State, states: Vec, cols: usize, - /// Incase an event needs a best guess column - last_selected_column: Option, - last_selected_input: Option + tab_index: Option, } impl Default for State { @@ -176,8 +140,7 @@ impl Default for State { files: combo_box::State::new(files), states: vec![ColState::default()], cols: 1, - last_selected_column: None, - last_selected_input: None, + tab_index: None, } } } @@ -189,51 +152,27 @@ impl State { } fn update(&mut self, msg: Message) -> Task { - // handle tab ordering - match msg { - Message::WordSearchInput(_, _) => self.last_selected_input = Some(SelectedInputBox::WordSearch), - Message::BibleSearchInput(_, _) => self.last_selected_input = Some(SelectedInputBox::VerseSearch), - Message::DeleteColumn(_) => self.last_selected_input = None, - _ => {} - } - - // try to set last_selected_column for messages with side effects - match msg { - // All events that give column index - Message::ErrorSelectingBible(i) | - Message::BibleSelected(i, _) | - Message::QuickSearch(i, _, _) | - Message::BibleSearchInput(i,_) | - Message::WordSearchInput(i, _) | - Message::BibleSearchSubmit(i) | - Message::SubmitWordSearch(i) | - Message::CopyText(i) | - Message::Clear(i) - => self.last_selected_column = Some(i), - Message::DeleteColumn(_) => self.last_selected_column = None, - _ => {} - } - // match normal messages match msg { - Message::ColSelected(i) => self.last_selected_column = Some(i), - Message::ColUnselected => self.last_selected_column = None, Message::RecievedEvent(event) => { - if let Event::Keyboard(kbd) =event { + if let Event::Keyboard(kbd) = event { if let iced::keyboard::Event::KeyReleased {key, modifiers, ..} = kbd { if let Key::Named(n) = key { if let Named::Tab = n { - if let Some(i) = self.last_selected_column { - if modifiers == Modifiers::SHIFT { - // Shirft + Tab - let next = SelectedInputBox::next(&self.last_selected_input); - let id = next.as_id_prefix(); - return text_input::focus(format!("{id}{}", i)); - } else { - // Tab + if let Some(idx) = self.tab_index { + let new_idx = if modifiers == Modifiers::SHIFT { idx-1 } else { idx+1 }; - // TODO prev - return text_input::focus(format!("verse-{}", i)); + // 2 because two buttons on each col + let new_idx = new_idx.clamp(0, (self.cols*2) as i32 -1); + + self.tab_index = Some(new_idx); + + let id = format!("tabId-{}", new_idx); + return text_input::focus(id); + } else { + if self.cols > 0 { + self.tab_index = Some(0); + return text_input::focus("tabId-0"); } } } @@ -241,8 +180,8 @@ impl State { } } } - Message::ErrorSelectingBible(i) => { - self.states[i].error = Some(String::new()); + Message::SetErrorMessage(i, m) => { + self.states[i].error = Some(m); } Message::DeleteColumn(idx) => { self.cols -= 1; @@ -263,18 +202,18 @@ impl State { // the Bible is held in memory in it's own variable. self.states[i].selected_file = Some(format!("{bible}")); self.states[i].bible_selected = Some(bible); - // automatically focus the search bar when done here - // return text_input::focus("bible-search"); + self.states[i].error = None; + } Err(err) => { eprintln!("{}", err); - return self.update(Message::ErrorSelectingBible(i)); + return self.update(Message::SetErrorMessage(i, err.to_string())); }, } }, Err(err) => { eprintln!("{}", err); - return self.update(Message::ErrorSelectingBible(i)); + return self.update(Message::SetErrorMessage(i, err.to_string())); } } } @@ -286,12 +225,8 @@ impl State { } return self.update(Message::BibleSearchSubmit(i)); } - Message::BibleSearchInput(i, query) => { - self.states[i].bible_search = query - }, - Message::WordSearchInput(i, query) => { - self.states[i].word_search = query - }, + Message::BibleSearchInput(i, query) => self.states[i].bible_search = query, + Message::WordSearchInput(i, query) => self.states[i].word_search = query, Message::BibleSearchSubmit(i) => { let mut splits = self.states[i].bible_search.split_whitespace(); let book = splits.next(); @@ -300,7 +235,25 @@ impl State { if let (Some(book), Some(chap_and_ver), Some(bible)) = (book, location, &self.states[i].bible_selected) { - self.states[i].scripture_body = bible::get(book, chap_and_ver, vec![bible]); + self.states[i].scripture_body = match bible::get(book, chap_and_ver, vec![bible]) { + Ok(s) => { + self.states[i].error = None; + Some(s) + }, + Err(s) => { + return self.update(Message::SetErrorMessage(i, s)); + }, + }; + } else { + if let None = book { + return self.update(Message::SetErrorMessage(i, format!("Error selecting book {:?}", book))); + } + if let None = location { + return self.update(Message::SetErrorMessage(i, format!("Error getting chapter and/or verse {:?}", location))); + } + if let None = &self.states[i].bible_selected { + return self.update(Message::SetErrorMessage(i, format!("Error getting selected bible"))); + } } } Message::SubmitWordSearch(i) => { @@ -336,26 +289,21 @@ impl State { row((0..self.cols).map(|col_index| { column![ // header - button("Delete Column") - .on_press_with(move || Message::DeleteColumn(col_index)) - .width(Length::Fill) - .style(button::danger), combo_box( &self.files, "Select Bible", self.states[col_index].selected_file.as_ref(), move |s| Message::BibleSelected(col_index, s) - ) - .on_open(Message::ColSelected(col_index)), + ), text_input( "Search query, ie: Gen 1:1", &self.states[col_index].bible_search ) - .id(format!("verse-{}", col_index)) + .id(format!("tabId-{}", (col_index*2)+0)) .on_input(move |s| Message::BibleSearchInput(col_index, s)) .on_submit(Message::BibleSearchSubmit(col_index)), widget::text_input("Word Search", &self.states[col_index].word_search) - .id(format!("word-{}", col_index)) + .id(format!("tabId-{}", (col_index*2)+1)) .on_input(move |s| Message::WordSearchInput(col_index, s)) .on_submit(Message::SubmitWordSearch(col_index)), row![ @@ -365,6 +313,11 @@ impl State { button("Copy Scripture") .on_press_with(move || Message::CopyText(col_index)) .style(button::primary), + button("Delete Column") + .on_press_with(move || Message::DeleteColumn(col_index)) + .style(button::danger), + text(format!("{:?}", self.states[col_index].error)) + .style(text::danger), ] .spacing(5), row![ diff --git a/src/texts/bible.rs b/src/texts/bible.rs index 04ead3e..72fbe10 100644 --- a/src/texts/bible.rs +++ b/src/texts/bible.rs @@ -102,7 +102,7 @@ pub fn search_for_word(word: &str, from_files: &Bible) -> Vec { found } -pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option { +pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Result { // expecting query to be in format: // Gen 1:2 // Gen 1:2-5 @@ -135,11 +135,11 @@ pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option { eprintln!("'{book}' is not a book"); - return None; + return Err(format!("'{book}' is not a book")); } }; @@ -162,10 +162,10 @@ pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option>() } else { - return None; + return Err(format!("Chapter number could not be parsed from {chapter}")); } } else { - return None; + return Err(format!("A chapter was not passed")); }; // Get the verse in each Bible @@ -190,9 +190,9 @@ pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option { @@ -206,13 +206,13 @@ pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option { // couldn't parse verse - return None; + return Err(format!("Couldn't parse '{:?}' or '{:?}' into verse numbers", start, end)); } } } @@ -226,7 +226,7 @@ pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option