summaryrefslogtreecommitdiffstats
path: root/src/canvas/dialogs/help_dialog.rs
blob: c75aef10dd320432fb2e10f831e7ec04f955a950 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::cmp::max;
use unicode_width::UnicodeWidthStr;

use tui::{
    backend::Backend,
    layout::{Alignment, Rect},
    terminal::Frame,
    widgets::{Block, Borders, Paragraph},
};

use crate::{app::App, canvas::Painter, constants};

const HELP_BASE: &str = " Help ── Esc to close ";

pub trait HelpDialog {
    fn draw_help_dialog<B: Backend>(
        &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
    );
}

impl HelpDialog for Painter {
    fn draw_help_dialog<B: Backend>(
        &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
    ) {
        let repeat_num = max(
            0,
            draw_loc.width as i32 - HELP_BASE.chars().count() as i32 - 2,
        );
        let help_title = format!(" Help ─{}─ Esc to close ", "─".repeat(repeat_num as usize));

        if app_state.is_force_redraw {
            // We must also recalculate how many lines are wrapping to properly get scrolling to work on
            // small terminal sizes... oh joy.

            let mut overflow_buffer = 0;
            let paragraph_width = draw_loc.width - 2;
            let mut prev_section_len = 0;

            constants::HELP_TEXT
                .iter()
                .enumerate()
                .for_each(|(itx, section)| {
                    let mut buffer = 0;

                    if itx == 0 {
                        section.iter().for_each(|text_line| {
                            buffer += UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16
                                / paragraph_width;
                        });

                        app_state.help_dialog_state.index_shortcuts[itx] = 0;
                        prev_section_len = section.len() as u16 + buffer;
                        overflow_buffer += buffer;
                    } else {
                        section.iter().for_each(|text_line| {
                            buffer += UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16
                                / paragraph_width;
                        });

                        app_state.help_dialog_state.index_shortcuts[itx] =
                            app_state.help_dialog_state.index_shortcuts[itx - 1]
                                + 1
                                + prev_section_len;
                        prev_section_len = section.len() as u16 + buffer;
                        overflow_buffer += buffer;
                    }
                });

            app_state.help_dialog_state.scroll_state.max_scroll_index =
                (self.styled_help_text.len() as u16
                    + (constants::HELP_TEXT.len() as u16 - 3)
                    + overflow_buffer)
                    .saturating_sub(draw_loc.height);

            // Fix if over-scrolled
            if app_state
                .help_dialog_state
                .scroll_state
                .current_scroll_index
                >= app_state.help_dialog_state.scroll_state.max_scroll_index
            {
                app_state
                    .help_dialog_state
                    .scroll_state
                    .current_scroll_index = app_state
                    .help_dialog_state
                    .scroll_state
                    .max_scroll_index
                    .saturating_sub(1);
            }
        }

        f.render_widget(
            Paragraph::new(self.styled_help_text.iter())
                .block(
                    Block::default()
                        .title(&help_title)
                        .title_style(self.colours.border_style)
                        .style(self.colours.border_style)
                        .borders(Borders::ALL)
                        .border_style(self.colours.border_style),
                )
                .style(self.colours.text_style)
                .alignment(Alignment::Left)
                .wrap(true)
                .scroll(
                    app_state
                        .help_dialog_state
                        .scroll_state
                        .current_scroll_index,
                ),
            draw_loc,
        );
    }
}