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
use crate::MenuItem;

pub trait SelectValue: Sized + Copy + PartialEq {
    fn next(&self) -> Self;
    fn name(&self) -> &'static str;
}

impl SelectValue for bool {
    fn next(&self) -> Self {
        !*self
    }

    fn name(&self) -> &'static str {
        match *self {
            // true => "O",
            // false => "O\r+\r#", // this only works for certain small fonts, unfortunately
            false => "[ ]",
            true => "[X]",
        }
    }
}

pub struct Select<'a, R, S: SelectValue> {
    title_text: &'a str,
    details: &'a str,
    convert: fn(S) -> R,
    value: S,
}

impl<'a, S: SelectValue> Select<'a, (), S> {
    pub fn new(title: &'a str, value: S) -> Self {
        Self {
            title_text: title,
            value,
            convert: |_| (),
            details: "",
        }
    }
}

impl<'a, R, S: SelectValue> Select<'a, R, S> {
    pub fn with_value_converter<R2: Copy>(self, convert: fn(S) -> R2) -> Select<'a, R2, S> {
        Select {
            convert,
            title_text: self.title_text,
            value: self.value,
            details: self.details,
        }
    }

    pub fn with_detail_text(self, details: &'a str) -> Self {
        Self { details, ..self }
    }
}

impl<'a, R, S: SelectValue> MenuItem for Select<'a, R, S> {
    type Data = R;

    fn interact(&mut self) -> R {
        self.value = self.value.next();
        (self.convert)(self.value)
    }

    fn title(&self) -> &str {
        self.title_text
    }

    fn details(&self) -> &str {
        self.details
    }

    fn value(&self) -> &str {
        self.value.name()
    }

    fn longest_value_str(&self) -> &str {
        let initial = self.value;
        let mut longest_str = initial.name();

        let mut current = initial.next();
        while current != initial {
            if current.name().len() > longest_str.len() {
                longest_str = current.name();
            }
            current = current.next();
        }

        longest_str
    }
}