working on tab... checkpoint
This commit is contained in:
		
							
								
								
									
										179
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,4 +1,7 @@
 | 
			
		||||
#![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::{
 | 
			
		||||
    Element, Length, Task, Theme, clipboard, color,
 | 
			
		||||
@@ -43,32 +46,14 @@ fn main() -> iced::Result {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ALL BUILTIN THEMES
 | 
			
		||||
    //    Light
 | 
			
		||||
    //    Dark
 | 
			
		||||
    //    Dracula
 | 
			
		||||
    //    Nord
 | 
			
		||||
    //    SolarizedLight
 | 
			
		||||
    //    SolarizedDark
 | 
			
		||||
    //    GruvboxLight
 | 
			
		||||
    //    GruvboxDark
 | 
			
		||||
    //    CatppuccinLatte
 | 
			
		||||
    //    CatppuccinFrappe
 | 
			
		||||
    //    CatppuccinMacchiato
 | 
			
		||||
    //    CatppuccinMocha
 | 
			
		||||
    //    TokyoNight
 | 
			
		||||
    //    TokyoNightStorm
 | 
			
		||||
    //    TokyoNightLight
 | 
			
		||||
    //    KanagawaWave
 | 
			
		||||
    //    KanagawaDragon
 | 
			
		||||
    //    KanagawaLotus
 | 
			
		||||
    //    Moonfly
 | 
			
		||||
    //    Nightfly
 | 
			
		||||
    //    Oxocarbon
 | 
			
		||||
    //    Ferra
 | 
			
		||||
    // THEMES
 | 
			
		||||
    //    Dark - KanagawaDragon
 | 
			
		||||
    //    Default - Nord
 | 
			
		||||
    //    Light - TokyoNightLight
 | 
			
		||||
 | 
			
		||||
    // GUI
 | 
			
		||||
    iced::application("Bible Study", State::update, State::view)
 | 
			
		||||
        .subscription(State::subscription)
 | 
			
		||||
        .theme(|_| Theme::Nord)
 | 
			
		||||
        .run()
 | 
			
		||||
}
 | 
			
		||||
@@ -85,6 +70,10 @@ enum Message {
 | 
			
		||||
    QuickSearch(usize, String, usize),
 | 
			
		||||
    AddColRight,
 | 
			
		||||
    DeleteColumn(usize),
 | 
			
		||||
    ErrorSelectingBible(usize),
 | 
			
		||||
    RecievedEvent(Event),
 | 
			
		||||
    ColSelected(usize),
 | 
			
		||||
    ColUnselected,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ColState {
 | 
			
		||||
@@ -96,6 +85,8 @@ struct ColState {
 | 
			
		||||
 | 
			
		||||
    word_search: String,
 | 
			
		||||
    word_search_results: Option<Vec<(String, bool)>>,
 | 
			
		||||
 | 
			
		||||
    error: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for ColState {
 | 
			
		||||
@@ -109,6 +100,41 @@ impl Default for ColState {
 | 
			
		||||
 | 
			
		||||
            word_search: String::new(),
 | 
			
		||||
            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>,
 | 
			
		||||
    states: Vec<ColState>,
 | 
			
		||||
    cols: usize,
 | 
			
		||||
    /// Incase an event needs a best guess column
 | 
			
		||||
    last_selected_column: Option<usize>,
 | 
			
		||||
    last_selected_input: Option<SelectedInputBox>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for State {
 | 
			
		||||
@@ -147,13 +176,74 @@ impl Default for State {
 | 
			
		||||
            files: combo_box::State::new(files),
 | 
			
		||||
            states: vec![ColState::default()],
 | 
			
		||||
            cols: 1,
 | 
			
		||||
            last_selected_column: None,
 | 
			
		||||
            last_selected_input: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl State {
 | 
			
		||||
 | 
			
		||||
    fn subscription(&self) -> Subscription<Message> {
 | 
			
		||||
        event::listen().map(Message::RecievedEvent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn update(&mut self, msg: Message) -> Task<Message> {
 | 
			
		||||
        // 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 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) => {
 | 
			
		||||
                self.cols -= 1;
 | 
			
		||||
                self.states.remove(idx);
 | 
			
		||||
@@ -165,14 +255,26 @@ impl State {
 | 
			
		||||
                self.states.push(ColState::default())
 | 
			
		||||
            }
 | 
			
		||||
            Message::BibleSelected(i, file) => {
 | 
			
		||||
                if let Ok(contents) = fs::read_to_string(&file) {
 | 
			
		||||
                    if let Ok(bible) = quick_xml::de::from_str::<bible::Bible>(&contents) {
 | 
			
		||||
                        // State is held technically in this variable, although
 | 
			
		||||
                        // 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");
 | 
			
		||||
                match fs::read_to_string(&file) {
 | 
			
		||||
                    Ok(contents) => {
 | 
			
		||||
                        match quick_xml::de::from_str::<bible::Bible>(&contents) {
 | 
			
		||||
                            Ok(bible)  => {
 | 
			
		||||
                                // State is held technically in this variable, although
 | 
			
		||||
                                // 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");
 | 
			
		||||
                            }
 | 
			
		||||
                            Err(err) => {
 | 
			
		||||
                                eprintln!("{}", err);
 | 
			
		||||
                                return self.update(Message::ErrorSelectingBible(i));
 | 
			
		||||
                            },
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    Err(err) => {
 | 
			
		||||
                        eprintln!("{}", err);
 | 
			
		||||
                        return self.update(Message::ErrorSelectingBible(i));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -184,8 +286,12 @@ 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();
 | 
			
		||||
@@ -218,13 +324,13 @@ impl State {
 | 
			
		||||
                self.states[i].word_search_results = None;
 | 
			
		||||
                self.states[i].bible_search = String::new();
 | 
			
		||||
                self.states[i].word_search = String::new();
 | 
			
		||||
                // return text_input::focus("bible-search");
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        Task::none()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn view(&self) -> Element<Message> {
 | 
			
		||||
        //TODO error message
 | 
			
		||||
        scrollable(
 | 
			
		||||
            row![
 | 
			
		||||
                row((0..self.cols).map(|col_index| {
 | 
			
		||||
@@ -239,14 +345,17 @@ impl State {
 | 
			
		||||
                            "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))
 | 
			
		||||
                        .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))
 | 
			
		||||
                            .on_input(move |s| Message::WordSearchInput(col_index, s))
 | 
			
		||||
                            .on_submit(Message::SubmitWordSearch(col_index)),
 | 
			
		||||
                        row![
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user