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 ResetBindingMode,
140}
141
142#[derive(Clone)]
143pub enum ScaleChange {
144 ToAbsolute,
145 ToRelative,
146 Adjust(f64),
147}
148
149impl Widget for SettingsWindow<'_> {
150 type Event = Vec<Event>;
151 type State = State;
152 type Style = ();
153
154 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
155 State {
156 ids: Ids::new(id_gen),
157 }
158 }
159
160 fn style(&self) -> Self::Style {}
161
162 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
163 common_base::prof_span!("SettingsWindow::update");
164 let widget::UpdateArgs { state, ui, .. } = args;
165
166 let mut events = Vec::new();
167 let tab_font_scale = 18;
168
169 Image::new(self.imgs.settings_bg)
171 .w_h(1052.0, 886.0)
172 .mid_top_with_margin_on(ui.window, 5.0)
173 .color(Some(UI_MAIN))
174 .set(state.ids.settings_bg, ui);
175
176 Image::new(self.imgs.settings_frame)
177 .w_h(1052.0, 886.0)
178 .middle_of(state.ids.settings_bg)
179 .color(Some(UI_HIGHLIGHT_0))
180 .set(state.ids.frame, ui);
181
182 Rectangle::fill_with([814.0, 834.0], color::TRANSPARENT)
184 .top_right_with_margins_on(state.ids.frame, 46.0, 2.0)
185 .set(state.ids.settings_content_align, ui);
186
187 Rectangle::fill_with([232.0, 814.0], color::TRANSPARENT)
189 .top_left_with_margins_on(state.ids.frame, 44.0, 2.0)
190 .scroll_kids()
191 .scroll_kids_vertically()
192 .set(state.ids.tabs_align, ui);
193
194 Image::new(self.imgs.settings)
196 .w_h(29.0 * 1.5, 25.0 * 1.5)
197 .top_left_with_margins_on(state.ids.frame, 2.0, 1.0)
198 .set(state.ids.icon, ui);
199 Text::new(
201 &self
202 .localized_strings
203 .get_msg(self.show.settings_tab.title_key()),
204 )
205 .mid_top_with_margin_on(state.ids.frame, 3.0)
206 .font_id(self.fonts.cyri.conrod_id)
207 .font_size(self.fonts.cyri.scale(29))
208 .color(TEXT_COLOR)
209 .set(state.ids.settings_title, ui);
210
211 if Button::image(self.imgs.close_button)
213 .w_h(24.0, 25.0)
214 .hover_image(self.imgs.close_btn_hover)
215 .press_image(self.imgs.close_btn_press)
216 .top_right_with_margins_on(state.ids.frame, 0.0, 0.0)
217 .set(state.ids.settings_close, ui)
218 .was_clicked()
219 {
220 events.push(Event::Close);
221 events.push(Event::ResetBindingMode); }
223
224 if state.ids.tabs.len() < SettingsTab::iter().len() {
226 state.update(|s| {
227 s.ids
228 .tabs
229 .resize(SettingsTab::iter().len(), &mut ui.widget_id_generator())
230 });
231 }
232 for (i, settings_tab) in SettingsTab::iter().enumerate() {
233 let tab_name = self.localized_strings.get_msg(settings_tab.name_key());
234 let mut button = Button::image(if self.show.settings_tab == settings_tab {
235 self.imgs.selection
236 } else {
237 self.imgs.nothing
238 })
239 .w_h(230.0, 48.0)
240 .hover_image(self.imgs.selection_hover)
241 .press_image(self.imgs.selection_press)
242 .image_color(color::rgba(1.0, 0.82, 0.27, 1.0))
243 .label(&tab_name)
244 .label_font_size(self.fonts.cyri.scale(tab_font_scale))
245 .label_font_id(self.fonts.cyri.conrod_id)
246 .label_color(TEXT_COLOR);
247
248 button = if i == 0 {
249 button.mid_top_with_margin_on(state.ids.tabs_align, 28.0)
250 } else {
251 button.down_from(state.ids.tabs[i - 1], 0.0)
252 };
253
254 if button.set(state.ids.tabs[i], ui).was_clicked() {
255 events.push(Event::ChangeTab(settings_tab));
256 events.push(Event::ResetBindingMode); }
258 }
259
260 let global_state = self.global_state;
262 let imgs = self.imgs;
263 let fonts = self.fonts;
264 let localized_strings = self.localized_strings;
265 match self.show.settings_tab {
266 SettingsTab::Interface => {
267 for change in
268 interface::Interface::new(global_state, imgs, fonts, localized_strings)
269 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
270 .wh_of(state.ids.settings_content_align)
271 .set(state.ids.interface, ui)
272 {
273 events.push(Event::SettingsChange(change.into()));
274 }
275 },
276 SettingsTab::Chat => {
277 for event in
278 chat::Chat::new(global_state, self.show, imgs, fonts, localized_strings)
279 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
280 .wh_of(state.ids.settings_content_align)
281 .set(state.ids.chat, ui)
282 {
283 match event {
284 chat::Event::ChatChange(change) => {
285 events.push(Event::SettingsChange(change.into()));
286 },
287 chat::Event::ChangeChatSettingsTab(index) => {
288 events.push(Event::ChangeChatSettingsTab(index));
289 },
290 }
291 }
292 },
293 SettingsTab::Gameplay => {
294 for change in gameplay::Gameplay::new(global_state, imgs, fonts, localized_strings)
295 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
296 .wh_of(state.ids.settings_content_align)
297 .set(state.ids.gameplay, ui)
298 {
299 events.push(Event::SettingsChange(change.into()));
300 }
301 },
302 SettingsTab::Controls => {
303 for change in controls::Controls::new(global_state, imgs, fonts, localized_strings)
304 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
305 .wh_of(state.ids.settings_content_align)
306 .set(state.ids.controls, ui)
307 {
308 events.push(Event::SettingsChange(change.into()));
309 }
310 },
311 SettingsTab::Video => {
312 for change in video::Video::new(
313 global_state,
314 imgs,
315 fonts,
316 localized_strings,
317 self.server_view_distance_limit,
318 self.fps,
319 )
320 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
321 .wh_of(state.ids.settings_content_align)
322 .set(state.ids.video, ui)
323 {
324 events.push(Event::SettingsChange(change.into()));
325 }
326 },
327 SettingsTab::Sound => {
328 for change in sound::Sound::new(global_state, imgs, fonts, localized_strings)
329 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
330 .wh_of(state.ids.settings_content_align)
331 .set(state.ids.sound, ui)
332 {
333 events.push(Event::SettingsChange(change.into()));
334 }
335 },
336 SettingsTab::Lang => {
337 for change in language::Language::new(global_state, imgs, fonts, localized_strings)
338 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
339 .wh_of(state.ids.settings_content_align)
340 .set(state.ids.language, ui)
341 {
342 events.push(Event::SettingsChange(change.into()));
343 }
344 },
345 SettingsTab::Networking => {
346 for change in networking::Networking::new(
347 global_state,
348 imgs,
349 fonts,
350 localized_strings,
351 self.server_view_distance_limit,
352 )
353 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
354 .wh_of(state.ids.settings_content_align)
355 .set(state.ids.networking, ui)
356 {
357 events.push(Event::SettingsChange(change.into()));
358 }
359 },
360 SettingsTab::Accessibility => {
361 for change in
362 accessibility::Accessibility::new(global_state, imgs, fonts, localized_strings)
363 .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
364 .wh_of(state.ids.settings_content_align)
365 .set(state.ids.accessibility, ui)
366 {
367 events.push(Event::SettingsChange(change.into()));
368 }
369 },
370 }
371
372 events
373 }
374}