ewin-prom 0.0.1

Simple editor for Window(GUI) users.No need to remember commands.
use crate::{
    ewin_core::{_cfg::key::keycmd::*, colors::*, def::*, global::*, log::*, model::*, util::*},
    model::*,
    prompt::choice::*,
};
use crossterm::{cursor::*, terminal::ClearType::*, terminal::*};
use std::collections::*;

impl Prompt {
    pub fn menu(&mut self) {
        Log::debug_key("Prompt.menu");

        self.disp_row_num = 11;

        let mut cont_1 = PromptCont::new(Some(PromptContPosi::First));
        cont_1.set_menu(self);
        self.cont_1 = cont_1;
        let mut cont_2 = PromptCont::new(Some(PromptContPosi::Second));
        cont_2.set_menu(self);
        self.cont_2 = cont_2;
        let mut cont_3 = PromptCont::new(Some(PromptContPosi::Third));
        cont_3.set_menu(self);
        self.cont_3 = cont_3;
    }

    pub fn left_down_choice_menu(&mut self, y: u16, x: u16) -> bool {
        Log::debug_key("left_down_choice_menu");

        Log::debug("yyy", &y);
        Log::debug("xxx", &x);
        Log::debug("self.cont_1.buf_row_posi", &self.cont_1.buf_row_posi);
        Log::debug("self.cont_1.buf_row_len", &self.cont_1.buf_row_len);

        Log::debug("self.cont_2.buf_row_posi", &self.cont_2.buf_row_posi);
        Log::debug("self.cont_2.buf_row_len", &self.cont_2.buf_row_len);

        Log::debug("self.cont_3.buf_row_posi", &self.cont_3.buf_row_posi);
        Log::debug("self.cont_3.buf_row_len", &self.cont_3.buf_row_len);

        let is_menu_select = match y {
            y if self.cont_1.buf_row_posi <= y && y <= self.cont_1.buf_row_posi + self.cont_1.buf_row_len => {
                if self.cont_1.left_down_choice(y, x) {
                    self.cont_posi = PromptContPosi::First;
                    true
                } else {
                    false
                }
            }
            y if self.cont_2.buf_row_posi <= y && y <= self.cont_2.buf_row_posi + self.cont_2.buf_row_len => {
                if self.cont_2.left_down_choice(y, x) {
                    self.cont_posi = PromptContPosi::Second;
                    true
                } else {
                    false
                }
            }
            y if self.cont_3.buf_row_posi <= y && y <= self.cont_3.buf_row_posi + self.cont_3.buf_row_len => {
                if self.cont_3.left_down_choice(y, x) {
                    self.cont_posi = PromptContPosi::Third;
                    true
                } else {
                    false
                }
            }
            _ => false,
        };
        if is_menu_select {
            Choices::change_show_choice(self);
        }
        return is_menu_select;
    }
    pub fn cache_menu(&mut self) {
        let map = self.cont_1.choices_map.clone();
        self.prom_menu.choices_map_cache.insert(PromptContPosi::First, map);
        let map = self.cont_2.choices_map.clone();
        self.prom_menu.choices_map_cache.insert(PromptContPosi::Second, map);
        let map = self.cont_3.choices_map.clone();
        self.prom_menu.choices_map_cache.insert(PromptContPosi::Third, map);

        self.prom_menu.cont_posi_cache = self.cont_posi;
    }

    pub fn draw_menu(&self, str_vec: &mut Vec<String>) {
        Log::debug_key("draw_menu");

        Prompt::set_draw_vec(str_vec, self.cont_1.buf_desc_row_posi, &self.cont_1.buf_desc.clone());
        self.cont_1.draw_choice_menu(str_vec);
        Prompt::set_draw_vec(str_vec, self.cont_2.buf_desc_row_posi, &self.cont_2.buf_desc.clone());
        self.cont_2.draw_choice_menu(str_vec);
        Prompt::set_draw_vec(str_vec, self.cont_3.buf_desc_row_posi, &self.cont_3.buf_desc.clone());
        self.cont_3.draw_choice_menu(str_vec);
    }

    pub fn draw_cur_menu(&self, str_vec: &mut Vec<String>) {
        match self.cont_posi {
            PromptContPosi::First => self.cont_1.draw_choice_cur(str_vec),
            PromptContPosi::Second => self.cont_2.draw_choice_cur(str_vec),
            PromptContPosi::Third => self.cont_3.draw_choice_cur(str_vec),
            _ => {}
        };
    }

    pub fn change_choice_vec_menu(&mut self, cur_direction: Direction) {
        Log::debug_key("Prompt.change_choice_vec_menu");
        match self.cont_posi {
            PromptContPosi::First => {
                if self.cont_1.get_choices().unwrap().set_vec_posi(cur_direction) {
                    if cur_direction == Direction::Down {
                        self.cont_posi = PromptContPosi::Second;
                    } else if cur_direction == Direction::Up {
                        Log::debug("self.cont_3.choices_map", &self.cont_3.choices_map);
                        self.cont_posi = if self.cont_3.is_show_choices_map() { PromptContPosi::Third } else { PromptContPosi::Second }
                    }
                }
            }
            PromptContPosi::Second => {
                if self.cont_2.get_choices().unwrap().set_vec_posi(cur_direction) {
                    if cur_direction == Direction::Down {
                        self.cont_posi = if self.cont_3.is_show_choices_map() { PromptContPosi::Third } else { PromptContPosi::First }
                    } else if cur_direction == Direction::Up {
                        self.cont_posi = PromptContPosi::First;
                    }
                }
            }
            PromptContPosi::Third => {
                if self.cont_3.get_choices().unwrap().set_vec_posi(cur_direction) {
                    if cur_direction == Direction::Down {
                        self.cont_posi = PromptContPosi::First;
                    } else if cur_direction == Direction::Up {
                        self.cont_posi = PromptContPosi::Second;
                    }
                }
            }
            _ => {}
        }
    }
}
impl PromptCont {
    pub fn set_menu(&mut self, prom: &mut Prompt) {
        match self.posi {
            PromptContPosi::First => {
                self.buf_row_len = 2;

                self.guide = format!("{}{}", Colors::get_msg_highlight_fg(), &LANG.select_menu);
                self.key_desc = format!(
                    "{}{}:{}{}Click  {}{}:{}{}  {}{}:{}Tab  {}{}:{}↑↓←→",
                    Colors::get_default_fg(),
                    &LANG.fixed,
                    Colors::get_msg_highlight_fg(),
                    Keybind::get_key_str(KeyCmd::Prom(P_Cmd::ConfirmPrompt)),
                    Colors::get_default_fg(),
                    &LANG.close,
                    Colors::get_msg_highlight_fg(),
                    Keybind::get_key_str(KeyCmd::Prom(P_Cmd::EscPrompt)),
                    Colors::get_default_fg(),
                    &LANG.move_setting_location,
                    Colors::get_msg_highlight_fg(),
                    Colors::get_default_fg(),
                    &LANG.candidate_change,
                    Colors::get_msg_highlight_fg(),
                );

                self.buf_desc = format!("{}{}{}", Colors::get_msg_highlight_fg(), &LANG.menu, Colors::get_default_fg());

                if prom.keycmd == KeyCmd::Edit(E_Cmd::OpenMenu) && prom.prom_menu.choices_map_cache.get(&PromptContPosi::First).is_some() {
                    self.choices_map = prom.prom_menu.choices_map_cache.get(&PromptContPosi::First).unwrap().clone();
                    prom.cont_posi = prom.prom_menu.cont_posi_cache;
                } else {
                    let mut choices = Choices::default();
                    let file = Keybind::get_menu_str(&LANG.file, KeyCmd::Edit(E_Cmd::OpenMenuFile));
                    let edit = Keybind::get_menu_str(&LANG.edit, KeyCmd::Edit(E_Cmd::OpenMenuEdit));
                    let search = Keybind::get_menu_str(&LANG.search, KeyCmd::Edit(E_Cmd::OpenMenuSearch));
                    let macros = Keybind::get_menu_str(&LANG.macros, KeyCmd::Edit(E_Cmd::OpenMenuMacro));

                    choices.vec = vec![vec![Choice::new(&file), Choice::new(&edit), Choice::new(&search), Choice::new(&macros)]];
                    choices.is_show = true;

                    // UNDEFINED because there are no parents
                    self.choices_map.insert(((USIZE_UNDEFINED, USIZE_UNDEFINED), (USIZE_UNDEFINED, USIZE_UNDEFINED)), choices);
                    Choices::set_shaping_choice_list(&mut self.choices_map);
                }
            }
            PromptContPosi::Second => {
                self.buf_row_len = 2;

                self.buf_desc = format!("{}{} 1{}", Colors::get_msg_highlight_fg(), &LANG.contents, Colors::get_default_fg());

                if prom.keycmd == KeyCmd::Edit(E_Cmd::OpenMenu) && prom.prom_menu.choices_map_cache.get(&PromptContPosi::Second).is_some() {
                    self.choices_map = prom.prom_menu.choices_map_cache.get(&PromptContPosi::Second).unwrap().clone();
                } else {
                    // file
                    let create_new = Keybind::get_menu_str(&LANG.create_new, KeyCmd::Edit(E_Cmd::NewTab));
                    let open_file = Keybind::get_menu_str(&LANG.open, KeyCmd::Edit(E_Cmd::OpenFile(OpenFileType::Normal)));
                    let encode = Keybind::get_menu_str(&LANG.encode, KeyCmd::Edit(E_Cmd::Encoding));
                    let vec_1 = vec![Choice::new(&create_new), Choice::new(&open_file), Choice::new(&LANG.save_as)];
                    let vec_2 = vec![Choice::new(&encode), Choice::new(&LANG.end_of_all_save)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1, vec_2];
                    self.choices_map.insert(((USIZE_UNDEFINED, USIZE_UNDEFINED), (0, 0)), choices);

                    // edit
                    let convert = Keybind::get_menu_str(&LANG.convert, KeyCmd::Edit(E_Cmd::OpenMenuConvert));
                    let format = &LANG.format;
                    let vec_1 = vec![Choice::new(&convert), Choice::new(&format)];
                    let select = Keybind::get_menu_str(&LANG.box_select, KeyCmd::Edit(E_Cmd::BoxSelectMode));
                    let vec_2 = vec![Choice::new(&select)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1, vec_2];
                    self.choices_map.insert(((USIZE_UNDEFINED, USIZE_UNDEFINED), (0, 1)), choices);
                    // search
                    let move_row = Keybind::get_menu_str(&LANG.move_row, KeyCmd::Edit(E_Cmd::MoveRow));
                    let vec_1 = vec![Choice::new(&move_row)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1];
                    self.choices_map.insert(((USIZE_UNDEFINED, USIZE_UNDEFINED), (0, 2)), choices);
                    // macros
                    let vec_1 = vec![Choice::new(&LANG.specify_file_and_exec_macro)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1];
                    self.choices_map.insert(((USIZE_UNDEFINED, USIZE_UNDEFINED), (0, 3)), choices);
                    Choices::set_shaping_choice_list(&mut self.choices_map);
                }
            }
            PromptContPosi::Third => {
                self.buf_row_len = 2;

                self.buf_desc = format!("{}{} 2{}", Colors::get_msg_highlight_fg(), &LANG.contents, Colors::get_default_fg());

                if prom.keycmd == KeyCmd::Edit(E_Cmd::OpenMenu) && prom.prom_menu.choices_map_cache.get(&PromptContPosi::Third).is_some() {
                    self.choices_map = prom.prom_menu.choices_map_cache.get(&PromptContPosi::Third).unwrap().clone();
                } else {
                    let vec_1 = vec![Choice::new(&LANG.to_lowercase), Choice::new(&LANG.to_half_width), Choice::new(&LANG.to_space)];
                    let vec_2 = vec![Choice::new(&LANG.to_uppercase), Choice::new(&LANG.to_full_width), Choice::new(&LANG.to_tab)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1, vec_2];
                    self.choices_map.insert(((0, 1), (0, 0)), choices);

                    let format_json = Keybind::get_menu_str(&LANG.json, KeyCmd::Edit(E_Cmd::Format(FmtType::JSON)));
                    let format_html = Keybind::get_menu_str(&LANG.html, KeyCmd::Edit(E_Cmd::Format(FmtType::HTML)));
                    let format_xml = Keybind::get_menu_str(&LANG.xml, KeyCmd::Edit(E_Cmd::Format(FmtType::XML)));
                    let vec_1 = vec![Choice::new(&format_json), Choice::new(&format_html), Choice::new(&format_xml)];
                    let mut choices = Choices::default();
                    choices.vec = vec![vec_1];
                    self.choices_map.insert(((0, 1), (0, 1)), choices);

                    Choices::set_shaping_choice_list(&mut self.choices_map);
                }
            }
            _ => {}
        };
    }

    pub fn draw_choice_menu(&self, str_vec: &mut Vec<String>) {
        for i in self.buf_row_posi..self.buf_row_posi + self.buf_row_len {
            str_vec.push(format!("{}{}", MoveTo(0, i as u16), Clear(CurrentLine)));
        }

        for (_, choices) in self.choices_map.iter() {
            if choices.is_show {
                for (y_idx, vec) in choices.vec.iter().enumerate() {
                    let mut row_width = 1;
                    for (x_idx, item) in vec.iter().enumerate() {
                        let item_str = if choices.is_show && choices.vec_y == y_idx && choices.vec_x == x_idx { format!("{}{}{}", Colors::get_msg_warning_inversion_fg_bg(), item.disp_name, Colors::get_hbar_fg_bg()) } else { format!("{}{}", Colors::get_hbar_fg_bg(), item.disp_name) };
                        str_vec.push(format!("{}{}", MoveTo(row_width, self.buf_row_posi + y_idx as u16), &item_str));

                        row_width += (get_str_width(&item.disp_name) + Choices::ITEM_MARGIN) as u16;
                    }
                }
            }
        }
    }

    pub fn set_default_choice_menu(&mut self, first_y: usize, first_x: usize, second_y: usize, second_x: usize) {
        Log::debug_key("set_default_choice_menu");
        Log::debug("self.p_cmd", &self.p_cmd);
        Log::debug("parent_vec_y", &first_y);
        Log::debug("parent_vec_x", &first_x);

        for (((grandparentst_y, grandparentst_x), (parent_y, parent_x)), choices) in self.choices_map.iter_mut() {
            for (y_idx, v) in choices.vec.iter_mut().enumerate() {
                for (x_idx, choice) in v.iter_mut().enumerate() {
                    match self.posi {
                        PromptContPosi::First => match self.keycmd {
                            KeyCmd::Edit(E_Cmd::OpenMenuFile) => {
                                if choice.name.contains(&LANG.file) {
                                    choices.vec_y = y_idx;
                                    choices.vec_x = x_idx;
                                }
                            }
                            KeyCmd::Edit(E_Cmd::OpenMenuEdit) => {
                                if choice.name.contains(&LANG.edit) {
                                    choices.vec_y = y_idx;
                                    choices.vec_x = x_idx;
                                }
                            }
                            KeyCmd::Edit(E_Cmd::OpenMenuSearch) => {
                                if choice.name.contains(&LANG.search) {
                                    choices.vec_y = y_idx;
                                    choices.vec_x = x_idx;
                                }
                            }
                            _ => {}
                        },
                        PromptContPosi::Second => {
                            choices.is_show = if parent_y == &second_y && parent_x == &second_x { true } else { false };
                        }
                        PromptContPosi::Third => {
                            choices.is_show = if grandparentst_y == &first_y && grandparentst_x == &first_x && parent_y == &second_y && parent_x == &second_y { true } else { false };
                        }
                        _ => {}
                    }
                }
            }
        }
    }
    pub fn is_show_choices_map(&mut self) -> bool {
        for (_, choices) in self.choices_map.iter() {
            if choices.is_show {
                return true;
            }
        }
        return false;
    }
}

#[derive(Debug, Clone)]
pub struct PromMenu {
    pub choices_map_cache: BTreeMap<PromptContPosi, HashMap<((usize, usize), (usize, usize)), Choices>>,
    pub cont_posi_cache: PromptContPosi,
}

impl Default for PromMenu {
    fn default() -> Self {
        PromMenu { choices_map_cache: BTreeMap::new(), cont_posi_cache: PromptContPosi::First }
    }
}