1mod accessibility;
2mod chat;
3mod controls;
4mod gameplay;
5mod interface;
6mod language;
7mod networking;
8mod sound;
9mod video;
10
11use crate::{
12 GlobalState,
13 hud::{Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, img_ids::Imgs},
14 session::settings_change::SettingsChange,
15 ui::fonts::Fonts,
16};
17use conrod_core::{
18 Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, color,
19 widget::{self, Button, Image, Rectangle, Text},
20 widget_ids,
21};
22use i18n::Localization;
23
24use strum::{EnumIter, IntoEnumIterator};
25
26widget_ids! {
27 struct Ids {
28 frame,
29 settings_bg,
30 tabs_align,
31 icon,
32 settings_close,
33 settings_title,
34 settings_content_align,
35
36 tabs[],
37 interface,
38 gameplay,
39 controls,
40 video,
41 sound,
42 language,
43 chat,
44 networking,
45 accessibility,
46 }
47}
48
49const RESET_BUTTONS_HEIGHT: f64 = 34.0;
50const RESET_BUTTONS_WIDTH: f64 = 155.0;
51
52#[derive(Debug, EnumIter, PartialEq, Eq)]
53pub enum SettingsTab {
54 Interface,
55 Chat,
56 Video,
57 Sound,
58 Gameplay,
59 Controls,
60 Lang,
61 Networking,
62 Accessibility,
63}
64impl SettingsTab {
65 fn name_key(&self) -> &str {
66 match self {
67 SettingsTab::Interface => "common-interface",
68 SettingsTab::Chat => "common-chat",
69 SettingsTab::Gameplay => "common-gameplay",
70 SettingsTab::Controls => "common-controls",
71 SettingsTab::Video => "common-video",
72 SettingsTab::Sound => "common-sound",
73 SettingsTab::Lang => "common-languages",
74 SettingsTab::Networking => "common-networking",
75 SettingsTab::Accessibility => "common-accessibility",
76 }
77 }
78
79 fn title_key(&self) -> &str {
80 match self {
81 SettingsTab::Interface => "common-interface_settings",
82 SettingsTab::Chat => "common-chat_settings",
83 SettingsTab::Gameplay => "common-gameplay_settings",
84 SettingsTab::Controls => "common-controls_settings",
85 SettingsTab::Video => "common-video_settings",
86 SettingsTab::Sound => "common-sound_settings",
87 SettingsTab::Lang => "common-language_settings",
88 SettingsTab::Networking => "common-networking_settings",
89 SettingsTab::Accessibility => "common-accessibility_settings",
90 }
91 }
92}
93
94#[derive(WidgetCommon)]
95pub struct SettingsWindow<'a> {
96 global_state: &'a GlobalState,
97 show: &'a Show,
98 imgs: &'a Imgs,
99 fonts: &'a Fonts,
100 localized_strings: &'a Localization,
101 server_view_distance_limit: Option<u32>,
102 fps: f32,
103 #[conrod(common_builder)]
104 common: widget::CommonBuilder,
105}
106
107impl<'a> SettingsWindow<'a> {
108 pub fn new(
109 global_state: &'a GlobalState,
110 show: &'a Show,
111 imgs: &'a Imgs,
112 fonts: &'a Fonts,
113 localized_strings: &'a Localization,
114 server_view_distance_limit: Option<u32>,
115 fps: f32,
116 ) -> Self {
117 Self {
118 global_state,
119 show,
120 imgs,
121 fonts,
122 localized_strings,
123 server_view_distance_limit,
124 fps,
125 common: widget::CommonBuilder::default(),
126 }
127 }
128}
129
130pub struct State {
131 ids: Ids,
132}
133
134pub enum Event {
135 ChangeTab(SettingsTab),
136 Close,
137 SettingsChange(SettingsChange),
138 ChangeChatSettingsTab(Option<usize>),
139}
140
141#[derive(Clone)]
142pub enum ScaleChange {
143 ToAbsolute,
144 ToRelative,
145 Adjust(f64),
146}
147
148impl Widget for SettingsWindow<'_> {
149 type Event = Vec<Event>;
150 type State = State;
151 type Style = ();
152
153 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
154 State {
155 ids: Ids::new(id_gen),
156 }
157 }
158
159 fn style(&self) -> Self::Style {}
160
161 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
162 common_base::prof_span!("SettingsWindow::update");
163 let widget::UpdateArgs { state, ui, .. } = args;
164
165 let mut events = Vec::new();
166 let tab_font_scale = 18;
167
168 Image::new(self.imgs.settings_bg)
170 .w_h(1052.0, 886.0)
171 .mid_top_with_margin_on(ui.window, 5.0)
172 .color(Some(UI_MAIN))
173 .set(state.ids.settings_bg, ui);
174
175 Image::new(self.imgs.settings_frame)
176 .w_h(1052.0, 886.0)
177 .middle_of(state.ids.settings_bg)
178 .color(Some(UI_HIGHLIGHT_0))
179 .set(state.ids.frame, ui);
180
181 Rectangle::fill_with([814.0, 834.0], color::TRANSPARENT)
183 .top_right_with_margins_on(state.ids.frame, 46.0, 2.0)
184 .set(state.ids.settings_content_align, ui);
185
186 Rectangle::fill_with([232.0, 814.0], color::TRANSPARENT)
188 .top_left_with_margins_on(state.ids.frame, 44.0, 2.0)
189 .scroll_kids()
190 .scroll_kids_vertically()
191 .set(state.ids.tabs_align, ui);
192
193 Image::new(self.imgs.settings)
195 .w_h(29.0 * 1.5, 25.0 * 1.5)
196 .top_left_with_margins_on(state.ids.frame, 2.0, 1.0)
197 .set(state.ids.icon, ui);
198 Text::new(
200 &self
201 .localized_strings
202 .get_msg(self.show.settings_tab.title_key()),
203 )
204 .mid_top_with_margin_on(state.ids.frame, 3.0)
205 .font_id(self.fonts.cyri.conrod_id)
206 .font_size(self.fonts.cyri.scale(29))
207 .color(TEXT_COLOR)
208 .set(state.ids.settings_title, ui);
209
210 if Button::image(self.imgs.close_button)
212 .w_h(24.0, 25.0)
213 .hover_image(self.imgs.close_btn_hover)
214 .press_image(self.imgs.close_btn_press)
215 .top_right_with_margins_on(state.ids.frame, 0.0, 0.0)
216 .set(state.ids.settings_close, ui)
217 .was_clicked()
218 {
219 events.push(Event::Close);
220 }
221
222 if state.ids.tabs.len() < SettingsTab::iter().len() {
224 state.update(|s| {
225 s.ids
226 .tabs
227 .resize(SettingsTab::iter().len(), &mut ui.widget_id_generator())
228 });
229 }
230 for (i, settings_tab) in SettingsTab::iter().enumerate() {
231 let tab_name = self.localized_strings.get_msg(settings_tab.name_key());
232 let mut button = Button::image(if self.show.settings_tab == settings_tab {
233 self.imgs.selection
234 } else {
235 self.imgs.nothing
236 })
237 .w_h(230.0, 48.0)
238 .hover_image(self.imgs.selection_hover)
239 .press_image(self.imgs.selection_press)
240 .image_color(color::rgba(1.0, 0.82, 0.27, 1.0))
241 .label(&tab_name)
242 .label_font_size(self.fonts.cyri.scale(tab_font_scale))
243 .label_font_id(self.fonts.cyri.conrod_id)
244 .label_color(TEXT_COLOR);
245
246 button = if i == 0 {
247 button.mid_top_with_margin_on(state.ids.tabs_align, 28.0)
248 } else {
249 button.down_from(state.ids.tabs[i - 1], 0.0)
250 };
251
252 if button.set(state.ids.tabs[i], ui).was_clicked() {
253 events.push(Event::ChangeTab(settings_tab));
254 }
255 }
256
257 let global_state = self.global_state;
259 let imgs = self.imgs;
260 let fonts = self.fonts;
261 let localized_strings = self.localized_strings;
262 match self.show.settings_tab {
263 SettingsTab::Interface => {
264 for change in
265 interface::Interface::new(global_state, imgs, fonts, localized_strings)
266 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
267 .wh_of(state.ids.settings_content_align)
268 .set(state.ids.interface, ui)
269 {
270 events.push(Event::SettingsChange(change.into()));
271 }
272 },
273 SettingsTab::Chat => {
274 for event in
275 chat::Chat::new(global_state, self.show, imgs, fonts, localized_strings)
276 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
277 .wh_of(state.ids.settings_content_align)
278 .set(state.ids.chat, ui)
279 {
280 match event {
281 chat::Event::ChatChange(change) => {
282 events.push(Event::SettingsChange(change.into()));
283 },
284 chat::Event::ChangeChatSettingsTab(index) => {
285 events.push(Event::ChangeChatSettingsTab(index));
286 },
287 }
288 }
289 },
290 SettingsTab::Gameplay => {
291 for change in gameplay::Gameplay::new(global_state, imgs, fonts, localized_strings)
292 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
293 .wh_of(state.ids.settings_content_align)
294 .set(state.ids.gameplay, ui)
295 {
296 events.push(Event::SettingsChange(change.into()));
297 }
298 },
299 SettingsTab::Controls => {
300 for change in controls::Controls::new(global_state, imgs, fonts, localized_strings)
301 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
302 .wh_of(state.ids.settings_content_align)
303 .set(state.ids.controls, ui)
304 {
305 events.push(Event::SettingsChange(change.into()));
306 }
307 },
308 SettingsTab::Video => {
309 for change in video::Video::new(
310 global_state,
311 imgs,
312 fonts,
313 localized_strings,
314 self.server_view_distance_limit,
315 self.fps,
316 )
317 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
318 .wh_of(state.ids.settings_content_align)
319 .set(state.ids.video, ui)
320 {
321 events.push(Event::SettingsChange(change.into()));
322 }
323 },
324 SettingsTab::Sound => {
325 for change in sound::Sound::new(global_state, imgs, fonts, localized_strings)
326 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
327 .wh_of(state.ids.settings_content_align)
328 .set(state.ids.sound, ui)
329 {
330 events.push(Event::SettingsChange(change.into()));
331 }
332 },
333 SettingsTab::Lang => {
334 for change in language::Language::new(global_state, imgs, fonts, localized_strings)
335 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
336 .wh_of(state.ids.settings_content_align)
337 .set(state.ids.language, ui)
338 {
339 events.push(Event::SettingsChange(change.into()));
340 }
341 },
342 SettingsTab::Networking => {
343 for change in networking::Networking::new(
344 global_state,
345 imgs,
346 fonts,
347 localized_strings,
348 self.server_view_distance_limit,
349 )
350 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
351 .wh_of(state.ids.settings_content_align)
352 .set(state.ids.networking, ui)
353 {
354 events.push(Event::SettingsChange(change.into()));
355 }
356 },
357 SettingsTab::Accessibility => {
358 for change in
359 accessibility::Accessibility::new(global_state, imgs, fonts, localized_strings)
360 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
361 .wh_of(state.ids.settings_content_align)
362 .set(state.ids.accessibility, ui)
363 {
364 events.push(Event::SettingsChange(change.into()));
365 }
366 },
367 }
368
369 events
370 }
371}