1mod logic;
2mod util;
3use cursive::{
4 event::Key,
5 theme::{BaseColor, Color},
6 view::{Nameable, Resizable, ScrollStrategy},
7 views::{
8 Button, Dialog, DummyView, EditView, LinearLayout, ListView, OnEventView, Panel,
9 ScrollView, TextView,
10 },
11 Cursive,
12};
13
14pub fn menu(s: &mut Cursive) {
16 s.add_global_callback(Key::Esc, |s| quit_window(s));
17 s.add_global_callback('q', |s| {
18 s.pop_layer();
19 });
20 s.add_layer(
21 OnEventView::new(
22 Dialog::around(
23 LinearLayout::vertical()
24 .child(TextView::new("Game settings").style(Color::Dark(BaseColor::Blue)))
25 .child(DummyView)
26 .child(util::setting_digit_num("Digit number: "))
27 .child(util::setting_pass_len("Code length: "))
28 .child(DummyView)
29 .child(Button::new("Start game", game)),
30 )
31 .title("mastermind-rs")
32 .button("Rules", rules)
33 .button("About", about)
34 .button("Quit", |s| s.quit()),
35 )
36 .on_event('q', |s| s.quit())
37 .on_event(Key::Esc, |s| s.quit()),
38 );
39}
40
41fn about(s: &mut Cursive) {
43 s.add_layer(
44 Dialog::around(
45 LinearLayout::vertical()
46 .child(util::banner())
47 .child(
48 TextView::new(
49 "
50A little game written for the sake of experience in writing
51Rust code. Also my first project using any kind of User Interface.
52 ",
53 )
54 .style(Color::Dark(BaseColor::Blue)),
55 )
56 .child(util::source_button(
57 "https://github.com/hiimsergey/mastermind-rs",
58 ))
59 .child(
60 TextView::new(
61 "
62Utilizes the \"cursive\" crate for building TUIs.
63 ",
64 )
65 .style(Color::Dark(BaseColor::Blue)),
66 )
67 .child(util::source_button("https://crates.io/crates/cursive"))
68 .child(
69 TextView::new(
70 "
71v. 0.2.10 - GPLv3 License ",
72 )
73 .style(Color::Dark(BaseColor::Blue)),
74 ),
75 )
76 .button("Ok", |s| {
77 s.pop_layer();
78 })
79 .title("About mastermind-rs")
80 .fixed_width(64),
81 );
82}
83
84fn game(s: &mut Cursive) {
86 let digit_num: u8 = s
87 .call_on_name("digit_num", |v: &mut TextView| {
88 let binding = v.get_content();
89 binding.source().parse().unwrap()
90 })
91 .unwrap();
92 let pass_len: u8 = s
93 .call_on_name("pass_len", |v: &mut TextView| {
94 let binding = v.get_content();
95 binding.source().parse().unwrap()
96 })
97 .unwrap();
98 let code = logic::gen_code(digit_num, pass_len);
99
100 let settings = TextView::new(format!(
101 "
102Digit number: {digit_num}
103Code length: {pass_len}"
104 ))
105 .style(Color::Dark(BaseColor::Blue));
106 let input = LinearLayout::horizontal()
107 .child(TextView::new("Your guess: "))
108 .child(
109 EditView::new()
110 .on_submit(move |s, name: &str| {
111 logic::check_guess(s, name, digit_num, &code);
112 })
113 .max_content_width(pass_len as usize)
114 .with_name("input")
115 .fixed_width(pass_len as usize + 1),
116 );
117
118 let list = Panel::new(ScrollView::new(ListView::new()).scroll_strategy(ScrollStrategy::StickToBottom).with_name("list"))
119 .fixed_height(12)
120 .fixed_width(2 * (pass_len as usize) + 14);
121 let game_sidebar = LinearLayout::vertical()
122 .child(settings)
123 .child(DummyView)
124 .child(input)
125 .child(DummyView.fixed_height(4))
126 .child(
127 Button::new("Menu", |s| {
128 s.pop_layer();
129 }),
130 )
131 .child(Button::new("Ragequit", |s| s.quit()));
132
133 s.add_layer(
134 Dialog::around(
135 LinearLayout::horizontal()
136 .child(list)
137 .child(DummyView)
138 .child(game_sidebar),
139 )
140 .title("Game"),
141 );
142}
143
144fn quit_window(s: &mut Cursive) {
146 s.add_layer(
147 OnEventView::new(
148 Dialog::around(
149 TextView::new("Do you want to \nquit the game?").style(Color::Dark(BaseColor::Red)),
150 )
151 .title("Confirm quit")
152 .button("No", |s| {
153 s.pop_layer();
154 })
155 .button("Yes", |s| s.quit()),
156 )
157 .on_event(Key::Esc, |s| {
158 s.pop_layer();
159 })
160 .on_event('q', |s| {
161 s.pop_layer();
162 }),
163 );
164}
165
166fn rules(s: &mut Cursive) {
168 s.add_layer(
169 Dialog::around(
170 LinearLayout::vertical()
171 .child(
172 TextView::new(
173 "Use the arrow keys or the mouse to navigate.
174Press q to close windows and Esc to quit the game.",
175 ),
176 )
177 .child(util::rules()),
178 )
179 .title("Rules")
180 .button("Ok", |s| {
181 s.pop_layer();
182 }),
183 );
184}