songbook 0.1.1

Songbook with TUI and CLI
Documentation
use ratatui::Frame;
use ratatui::layout::{Constraint, Layout};
use ratatui::widgets::{Block, Paragraph, List, ListItem, Table, Row};
use ratatui::prelude::*;
use Constraint::{Percentage, Fill, Length};

use super::{
    song_formater,
    Focus,
    App,
};


impl App {
    pub fn draw_main_screen(&mut self, frame: &mut Frame) {
        let horizontal = if self.hide_lib {
            Layout::horizontal([Percentage(0), Percentage(100)])
        } else {
            Layout::horizontal([Percentage(25), Percentage(75)])
        };
        let [lib_area, song_area] = horizontal.areas(frame.area());


        let focus_color = self.config.colors.get_focus_color();
        let unfocus_color = self.config.colors.get_unfocus_color();
        let directories_color = self.config.colors.get_directories_color();
        let songs_color = self.config.colors.get_songs_color();
        let title_color = self.config.colors.get_title_color();
        let chords_color = self.config.colors.get_chords_color();
        let rhythm_color = self.config.colors.get_rhythm_color();
        let notes_color = self.config.colors.get_notes_color();
        let text_color = self.config.colors.get_text_color();


        let mut items: Vec<ListItem> = Vec::new();
        for (name, path) in &self.lib_list {
            let mut style = Style::new();
            if path.is_dir() { style = style.fg(directories_color); }
            else if path.is_file() { style = style.fg(songs_color); }
            if let Some(c_path) = &self.cutted_path && c_path == path { style = style.dim(); }
            if let Some(c_path) = &self.copied_path && c_path == path { style = style.green(); }
            if self.selected_paths.iter().any(|p| p == path) {
                match self.action_with_selected_paths {
                    super::ActionWithSelectedPaths::Cp => style = style.green(),
                    super::ActionWithSelectedPaths::Mv => style = style.dim(),
                    super::ActionWithSelectedPaths::Nothing => style = style.bold(),
                }
            }
            items.push(ListItem::new(name.as_str()).style(style));
        }

        if !self.hide_lib {
            let list = List::new(items)
                .highlight_style(Style::new())
                .highlight_symbol("->")
                .block(
                    Block::bordered().title(
                        self.current_dir
                            .file_name()
                            .and_then(|n| n.to_str())
                            .unwrap_or("library")
                        )

                        .border_style(if self.focus == Focus::Library {
                            Style::new().fg(focus_color)
                        } else {
                            Style::new().fg(unfocus_color)
                        })
                );
            frame.render_stateful_widget(list, lib_area, &mut self.lib_list_state);
        }


        let song_block = Block::bordered()
            .border_style(if self.focus == Focus::Song {
                Style::new().fg(focus_color)
            } else {
                Style::new().fg(unfocus_color)
            });
        let inner_song_area = song_block.inner(song_area);

        let title: String;
        let title_top: String;
        let song = if let Some((song, _p)) = &self.current_song {
            title = format!("{} - {}", song.metadata.artist, song.metadata.title);

            let mut t_top_buf = String::new();
            if let Some(key) = &song.metadata.key {
                t_top_buf.push_str("Key: ");
                t_top_buf.push_str(&if let Some(capo) = &song.metadata.capo {
                    format!("{}/({})",
                        key.transpose(0 - <u8 as Into<i32>>::into(*capo)).to_string(),
                        key.to_string()
                    )
                } else {
                    key.to_string()
                });
            }
            if let Some(capo) = &song.metadata.capo {
                if !t_top_buf.is_empty() { t_top_buf.push_str(", ") }
                t_top_buf.push_str("Capo: ");
                t_top_buf.push_str(&capo.to_string());
            }
            title_top = t_top_buf;



            let height = <u16 as Into<usize>>::into(inner_song_area.height);
            let width = <u16 as Into<usize>>::into(inner_song_area.width);
            self.song_area_height = Some(height);
            self.song_area_width = Some(width);

            let (p, lines, columns) = song_formater::get_as_paragraph(
                &song,
                width,
                self.show_chords,
                self.show_rhythm,
                self.show_fingerings,
                self.show_notes,
                [title_color, chords_color, rhythm_color, notes_color, text_color]
            );

            self.scroll_y_max = lines.saturating_sub(height);
            self.scroll_x_max = columns.saturating_sub(width);

            p.scroll( (self.scroll_y, self.scroll_x) )
        } else {
            title = "Nothing to show".to_string();
            title_top = String::new();
            Paragraph::default()
        }.block(
            song_block
                .title(title)
                .title_top(Line::from(title_top).right_aligned())
                .title_bottom(Line::from(self.long_command.as_str()).right_aligned())
                .title_bottom(Line::from(
                    if self.autoscroll { self.autoscroll_speed.as_millis().to_string() + "ms" }
                    else { String::new() }
                ))
        );
        frame.render_widget(song, song_area);
    }



    pub fn draw_help_screen(&mut self, frame: &mut Frame) {
        let rows = [
            Row::new(vec![
                Line::default(),
                Line::from("Library").centered(),
                Line::default()
            ]),
            Row::new(vec![
                Line::default(),
                Line::from("---------").centered(),
                Line::default()
            ]),

            Row::new(vec![
                Line::from("j, Down"),
                Line::default(),
                Line::from("Go down")
            ]),

            Row::new(vec![
                Line::from("k, Up"),
                Line::default(),
                Line::from("Go up")
            ]),

            Row::new(vec![
                Line::from("h, Left, Backspace"),
                Line::default(),
                Line::from("Go back")
            ]),

            Row::new(vec![
                Line::from("l, Right, Enter"),
                Line::default(),
                Line::from("Open dir/song")
            ]),

            Row::new(vec![
                Line::from("c"),
                Line::default(),
                Line::from("Copy dir/song")
            ]),

            Row::new(vec![
                Line::from("x"),
                Line::default(),
                Line::from("Cut dir/song")
            ]),

            Row::new(vec![
                Line::from("p"),
                Line::default(),
                Line::from("Paste dir/song")
            ]),

            Row::new(vec![
                Line::from("Space"),
                Line::default(),
                Line::from("Multiple select")
            ]),

            Row::new(vec![
                Line::from("S"),
                Line::default(),
                Line::from("Sort all songs")
            ]),

            Row::new(vec![
                Line::from("D"),
                Line::default(),
                Line::from("Delete dir/song")
            ]),

            Row::new(vec![
                Line::from("N(dir name)"),
                Line::default(),
                Line::from("Create dir")
            ]),

            Row::new(vec![
                Line::from("R(new name)"),
                Line::default(),
                Line::from("Rename dir/song")
            ]),

            Row::new(vec![
                Line::from("F(find query)"),
                Line::default(),
                Line::from("Find")
            ]),

            Row::new(vec![
                Line::from("A(e/t/c/s)"),
                Line::default(),
                Line::from("Add song")
            ]),
            Row::new(vec!["", " ", ""]),


            Row::new(vec![
                Line::default(),
                Line::from("Song").centered(),
                Line::default()
            ]),
            Row::new(vec![
                Line::from(""),
                Line::from("------").centered(),
                Line::from("")
            ]),

            Row::new(vec![
                Line::from("j, Down"),
                Line::default(),
                Line::from("Scroll down")
            ]),

            Row::new(vec![
                Line::from("k, Up"),
                Line::default(),
                Line::from("Scroll up")
            ]),

            Row::new(vec![
                Line::from("h, Left"),
                Line::default(),
                Line::from("Scroll left")
            ]),

            Row::new(vec![
                Line::from("l, Right"),
                Line::default(),
                Line::from("Scroll right")
            ]),

            Row::new(vec![
                Line::from("J, PageDown"),
                Line::default(),
                Line::from("Scroll page down")
            ]),

            Row::new(vec![
                Line::from("K, PageUp"),
                Line::default(),
                Line::from("Scroll page up")
            ]),

            Row::new(vec![
                Line::from("Home"),
                Line::default(),
                Line::from("Scroll to start")
            ]),

            Row::new(vec![
                Line::from("End"),
                Line::default(),
                Line::from("Scroll to end")
            ]),

            Row::new(vec![
                Line::from("c"),
                Line::default(),
                Line::from("Toggle chords")
            ]),

            Row::new(vec![
                Line::from("r"),
                Line::default(),
                Line::from("Toggle rhythm")
            ]),

            Row::new(vec![
                Line::from("f"),
                Line::default(),
                Line::from("Toggle fingerings")
            ]),

            Row::new(vec![
                Line::from("n"),
                Line::default(),
                Line::from("Toggle notes")
            ]),

            Row::new(vec![
                Line::from(";"),
                Line::default(),
                Line::from("Toggle lib")
            ]),

            Row::new(vec![
                Line::from("e"),
                Line::default(),
                Line::from("Edit song")
            ]),

            Row::new(vec![
                Line::from("R"),
                Line::default(),
                Line::from("Generate rhythm")
            ]),

            Row::new(vec![
                Line::from("a"),
                Line::default(),
                Line::from("Toggle autoscroll")
            ]),

            Row::new(vec![
                Line::from("h, Left"),
                Line::default(),
                Line::from("- autoscroll speed")
            ]),

            Row::new(vec![
                Line::from("l, Right"),
                Line::default(),
                Line::from("+ autoscroll speed")
            ]),

            Row::new(vec![
                Line::from("S(speed)"),
                Line::default(),
                Line::from("Set autoscroll speed")
            ]),

            Row::new(vec![
                Line::from("T(+/-num)"),
                Line::default(),
                Line::from("Transpose song")
            ]),

            Row::new(vec![
                Line::from("C(fret num)"),
                Line::default(),
                Line::from("Set capo")
            ]),

        ];

        let width = [Length(20), Fill(1), Length(20)];
        let table = Table::new(rows, width)
            .row_highlight_style(Style::new().reversed())
            .block(Block::bordered().title(Line::from(" Help ").centered()));


        frame.render_stateful_widget(table, frame.area(), &mut self.help_table_state);
    }
}