working on tab... checkpoint
This commit is contained in:
		
							
								
								
									
										167
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										167
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,4 +1,7 @@
 | 
				
			|||||||
#![feature(iter_map_windows)]
 | 
					#![feature(iter_map_windows)]
 | 
				
			||||||
 | 
					use iced::keyboard::key::Named;
 | 
				
			||||||
 | 
					use iced::keyboard::{Key, Modifiers};
 | 
				
			||||||
 | 
					use iced::{event, task, Event, Subscription};
 | 
				
			||||||
use iced::widget::scrollable;
 | 
					use iced::widget::scrollable;
 | 
				
			||||||
use iced::{
 | 
					use iced::{
 | 
				
			||||||
    Element, Length, Task, Theme, clipboard, color,
 | 
					    Element, Length, Task, Theme, clipboard, color,
 | 
				
			||||||
@@ -43,32 +46,14 @@ fn main() -> iced::Result {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ALL BUILTIN THEMES
 | 
					    // THEMES
 | 
				
			||||||
    //    Light
 | 
					    //    Dark - KanagawaDragon
 | 
				
			||||||
    //    Dark
 | 
					    //    Default - Nord
 | 
				
			||||||
    //    Dracula
 | 
					    //    Light - TokyoNightLight
 | 
				
			||||||
    //    Nord
 | 
					 | 
				
			||||||
    //    SolarizedLight
 | 
					 | 
				
			||||||
    //    SolarizedDark
 | 
					 | 
				
			||||||
    //    GruvboxLight
 | 
					 | 
				
			||||||
    //    GruvboxDark
 | 
					 | 
				
			||||||
    //    CatppuccinLatte
 | 
					 | 
				
			||||||
    //    CatppuccinFrappe
 | 
					 | 
				
			||||||
    //    CatppuccinMacchiato
 | 
					 | 
				
			||||||
    //    CatppuccinMocha
 | 
					 | 
				
			||||||
    //    TokyoNight
 | 
					 | 
				
			||||||
    //    TokyoNightStorm
 | 
					 | 
				
			||||||
    //    TokyoNightLight
 | 
					 | 
				
			||||||
    //    KanagawaWave
 | 
					 | 
				
			||||||
    //    KanagawaDragon
 | 
					 | 
				
			||||||
    //    KanagawaLotus
 | 
					 | 
				
			||||||
    //    Moonfly
 | 
					 | 
				
			||||||
    //    Nightfly
 | 
					 | 
				
			||||||
    //    Oxocarbon
 | 
					 | 
				
			||||||
    //    Ferra
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // GUI
 | 
					    // GUI
 | 
				
			||||||
    iced::application("Bible Study", State::update, State::view)
 | 
					    iced::application("Bible Study", State::update, State::view)
 | 
				
			||||||
 | 
					        .subscription(State::subscription)
 | 
				
			||||||
        .theme(|_| Theme::Nord)
 | 
					        .theme(|_| Theme::Nord)
 | 
				
			||||||
        .run()
 | 
					        .run()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -85,6 +70,10 @@ enum Message {
 | 
				
			|||||||
    QuickSearch(usize, String, usize),
 | 
					    QuickSearch(usize, String, usize),
 | 
				
			||||||
    AddColRight,
 | 
					    AddColRight,
 | 
				
			||||||
    DeleteColumn(usize),
 | 
					    DeleteColumn(usize),
 | 
				
			||||||
 | 
					    ErrorSelectingBible(usize),
 | 
				
			||||||
 | 
					    RecievedEvent(Event),
 | 
				
			||||||
 | 
					    ColSelected(usize),
 | 
				
			||||||
 | 
					    ColUnselected,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ColState {
 | 
					struct ColState {
 | 
				
			||||||
@@ -96,6 +85,8 @@ struct ColState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    word_search: String,
 | 
					    word_search: String,
 | 
				
			||||||
    word_search_results: Option<Vec<(String, bool)>>,
 | 
					    word_search_results: Option<Vec<(String, bool)>>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    error: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for ColState {
 | 
					impl Default for ColState {
 | 
				
			||||||
@@ -109,6 +100,41 @@ impl Default for ColState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            word_search: String::new(),
 | 
					            word_search: String::new(),
 | 
				
			||||||
            word_search_results: None,
 | 
					            word_search_results: None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            error: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq)]
 | 
				
			||||||
 | 
					enum SelectedInputBox {
 | 
				
			||||||
 | 
					    Bible,
 | 
				
			||||||
 | 
					    VerseSearch,
 | 
				
			||||||
 | 
					    WordSearch,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl SelectedInputBox {
 | 
				
			||||||
 | 
					    fn in_order() -> Vec<Self> {
 | 
				
			||||||
 | 
					        vec![
 | 
				
			||||||
 | 
					            SelectedInputBox::Bible,
 | 
				
			||||||
 | 
					            SelectedInputBox::VerseSearch,
 | 
				
			||||||
 | 
					            SelectedInputBox::WordSearch
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn next(current: &Option<Self>) -> 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-",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -117,6 +143,9 @@ struct State {
 | 
				
			|||||||
    files: combo_box::State<String>,
 | 
					    files: combo_box::State<String>,
 | 
				
			||||||
    states: Vec<ColState>,
 | 
					    states: Vec<ColState>,
 | 
				
			||||||
    cols: usize,
 | 
					    cols: usize,
 | 
				
			||||||
 | 
					    /// Incase an event needs a best guess column
 | 
				
			||||||
 | 
					    last_selected_column: Option<usize>,
 | 
				
			||||||
 | 
					    last_selected_input: Option<SelectedInputBox>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for State {
 | 
					impl Default for State {
 | 
				
			||||||
@@ -147,13 +176,74 @@ impl Default for State {
 | 
				
			|||||||
            files: combo_box::State::new(files),
 | 
					            files: combo_box::State::new(files),
 | 
				
			||||||
            states: vec![ColState::default()],
 | 
					            states: vec![ColState::default()],
 | 
				
			||||||
            cols: 1,
 | 
					            cols: 1,
 | 
				
			||||||
 | 
					            last_selected_column: None,
 | 
				
			||||||
 | 
					            last_selected_input: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl State {
 | 
					impl State {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn subscription(&self) -> Subscription<Message> {
 | 
				
			||||||
 | 
					        event::listen().map(Message::RecievedEvent)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update(&mut self, msg: Message) -> Task<Message> {
 | 
					    fn update(&mut self, msg: Message) -> Task<Message> {
 | 
				
			||||||
 | 
					        // handle tab ordering
 | 
				
			||||||
        match msg {
 | 
					        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 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        // TODO prev
 | 
				
			||||||
 | 
					                                        return text_input::focus(format!("verse-{}", i));
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Message::ErrorSelectingBible(i) => {
 | 
				
			||||||
 | 
					                self.states[i].error = Some(String::new());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            Message::DeleteColumn(idx) => {
 | 
					            Message::DeleteColumn(idx) => {
 | 
				
			||||||
                self.cols -= 1;
 | 
					                self.cols -= 1;
 | 
				
			||||||
                self.states.remove(idx);
 | 
					                self.states.remove(idx);
 | 
				
			||||||
@@ -165,8 +255,10 @@ impl State {
 | 
				
			|||||||
                self.states.push(ColState::default())
 | 
					                self.states.push(ColState::default())
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Message::BibleSelected(i, file) => {
 | 
					            Message::BibleSelected(i, file) => {
 | 
				
			||||||
                if let Ok(contents) = fs::read_to_string(&file) {
 | 
					                match fs::read_to_string(&file) {
 | 
				
			||||||
                    if let Ok(bible) = quick_xml::de::from_str::<bible::Bible>(&contents) {
 | 
					                    Ok(contents) => {
 | 
				
			||||||
 | 
					                        match quick_xml::de::from_str::<bible::Bible>(&contents) {
 | 
				
			||||||
 | 
					                            Ok(bible)  => {
 | 
				
			||||||
                                // State is held technically in this variable, although
 | 
					                                // State is held technically in this variable, although
 | 
				
			||||||
                                // the Bible is held in memory in it's own variable.
 | 
					                                // the Bible is held in memory in it's own variable.
 | 
				
			||||||
                                self.states[i].selected_file = Some(format!("{bible}"));
 | 
					                                self.states[i].selected_file = Some(format!("{bible}"));
 | 
				
			||||||
@@ -174,6 +266,16 @@ impl State {
 | 
				
			|||||||
                                // automatically focus the search bar when done here
 | 
					                                // automatically focus the search bar when done here
 | 
				
			||||||
                                // return text_input::focus("bible-search");
 | 
					                                // return text_input::focus("bible-search");
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					                            Err(err) => {
 | 
				
			||||||
 | 
					                                eprintln!("{}", err);
 | 
				
			||||||
 | 
					                                return self.update(Message::ErrorSelectingBible(i));
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    Err(err) => {
 | 
				
			||||||
 | 
					                        eprintln!("{}", err);
 | 
				
			||||||
 | 
					                        return self.update(Message::ErrorSelectingBible(i));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Message::QuickSearch(i, s, result_index) => {
 | 
					            Message::QuickSearch(i, s, result_index) => {
 | 
				
			||||||
@@ -184,8 +286,12 @@ impl State {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return self.update(Message::BibleSearchSubmit(i));
 | 
					                return self.update(Message::BibleSearchSubmit(i));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Message::BibleSearchInput(i, query) => self.states[i].bible_search = query,
 | 
					            Message::BibleSearchInput(i, query) => {
 | 
				
			||||||
            Message::WordSearchInput(i, query) => self.states[i].word_search = query,
 | 
					                self.states[i].bible_search = query
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Message::WordSearchInput(i, query) => {
 | 
				
			||||||
 | 
					                self.states[i].word_search = query
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            Message::BibleSearchSubmit(i) => {
 | 
					            Message::BibleSearchSubmit(i) => {
 | 
				
			||||||
                let mut splits = self.states[i].bible_search.split_whitespace();
 | 
					                let mut splits = self.states[i].bible_search.split_whitespace();
 | 
				
			||||||
                let book = splits.next();
 | 
					                let book = splits.next();
 | 
				
			||||||
@@ -218,13 +324,13 @@ impl State {
 | 
				
			|||||||
                self.states[i].word_search_results = None;
 | 
					                self.states[i].word_search_results = None;
 | 
				
			||||||
                self.states[i].bible_search = String::new();
 | 
					                self.states[i].bible_search = String::new();
 | 
				
			||||||
                self.states[i].word_search = String::new();
 | 
					                self.states[i].word_search = String::new();
 | 
				
			||||||
                // return text_input::focus("bible-search");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        Task::none()
 | 
					        Task::none()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn view(&self) -> Element<Message> {
 | 
					    fn view(&self) -> Element<Message> {
 | 
				
			||||||
 | 
					        //TODO error message
 | 
				
			||||||
        scrollable(
 | 
					        scrollable(
 | 
				
			||||||
            row![
 | 
					            row![
 | 
				
			||||||
                row((0..self.cols).map(|col_index| {
 | 
					                row((0..self.cols).map(|col_index| {
 | 
				
			||||||
@@ -239,14 +345,17 @@ impl State {
 | 
				
			|||||||
                            "Select Bible",
 | 
					                            "Select Bible",
 | 
				
			||||||
                            self.states[col_index].selected_file.as_ref(),
 | 
					                            self.states[col_index].selected_file.as_ref(),
 | 
				
			||||||
                            move |s| Message::BibleSelected(col_index, s)
 | 
					                            move |s| Message::BibleSelected(col_index, s)
 | 
				
			||||||
                        ),
 | 
					                        )
 | 
				
			||||||
 | 
					                        .on_open(Message::ColSelected(col_index)),
 | 
				
			||||||
                        text_input(
 | 
					                        text_input(
 | 
				
			||||||
                            "Search query, ie: Gen 1:1",
 | 
					                            "Search query, ie: Gen 1:1",
 | 
				
			||||||
                            &self.states[col_index].bible_search
 | 
					                            &self.states[col_index].bible_search
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
 | 
					                        .id(format!("verse-{}", col_index))
 | 
				
			||||||
                        .on_input(move |s| Message::BibleSearchInput(col_index, s))
 | 
					                        .on_input(move |s| Message::BibleSearchInput(col_index, s))
 | 
				
			||||||
                        .on_submit(Message::BibleSearchSubmit(col_index)),
 | 
					                        .on_submit(Message::BibleSearchSubmit(col_index)),
 | 
				
			||||||
                        widget::text_input("Word Search", &self.states[col_index].word_search)
 | 
					                        widget::text_input("Word Search", &self.states[col_index].word_search)
 | 
				
			||||||
 | 
					                            .id(format!("word-{}", col_index))
 | 
				
			||||||
                            .on_input(move |s| Message::WordSearchInput(col_index, s))
 | 
					                            .on_input(move |s| Message::WordSearchInput(col_index, s))
 | 
				
			||||||
                            .on_submit(Message::SubmitWordSearch(col_index)),
 | 
					                            .on_submit(Message::SubmitWordSearch(col_index)),
 | 
				
			||||||
                        row![
 | 
					                        row![
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user