1use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
2
3use crate::{
4 GlobalState,
5 audio::SfxChannelSettings,
6 hud::{MENU_BG, TEXT_COLOR, TEXT_COLOR_GREY, img_ids::Imgs},
7 session::settings_change::Audio::{self as AudioChange, *},
8 ui::{ImageSlider, ToggleButton, fonts::Fonts},
9};
10use conrod_core::{
11 Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, color,
12 position::{Align, Relative},
13 widget::{self, Button, DropDownList, Rectangle, Scrollbar, Text},
14 widget_ids,
15};
16use i18n::Localization;
17
18widget_ids! {
19 struct Ids {
20 window,
21 window_r,
22 window_scrollbar,
23 master_volume_text,
24 master_volume_slider,
25 master_volume_number,
26 master_volume_muted,
27 inactive_master_volume_text,
28 inactive_master_volume_slider,
29 inactive_master_volume_number,
30 inactive_master_volume_muted,
31 music_volume_text,
32 music_volume_slider,
33 music_volume_number,
34 music_volume_muted,
35 sfx_volume_text,
36 sfx_volume_slider,
37 sfx_volume_number,
38 sfx_volume_muted,
39 ambience_volume_text,
40 ambience_volume_slider,
41 ambience_volume_number,
42 ambience_volume_muted,
43 rain_ambience_label,
44 rain_ambience_checkbox,
45 music_spacing_text,
46 music_spacing_slider,
47 music_spacing_number,
48 reset_sound_button,
49 combat_music_toggle_label,
50 combat_music_toggle_button,
51 sfx_channels_label,
52 sfx_channels_list,
53 }
56}
57
58#[derive(WidgetCommon)]
59pub struct Sound<'a> {
60 global_state: &'a GlobalState,
61 imgs: &'a Imgs,
62 fonts: &'a Fonts,
63 localized_strings: &'a Localization,
64 #[conrod(common_builder)]
65 common: widget::CommonBuilder,
66}
67impl<'a> Sound<'a> {
68 pub fn new(
69 global_state: &'a GlobalState,
70 imgs: &'a Imgs,
71 fonts: &'a Fonts,
72 localized_strings: &'a Localization,
73 ) -> Self {
74 Self {
75 global_state,
76 imgs,
77 fonts,
78 localized_strings,
79 common: widget::CommonBuilder::default(),
80 }
81 }
82}
83
84pub struct State {
85 ids: Ids,
86}
87
88impl Widget for Sound<'_> {
89 type Event = Vec<AudioChange>;
90 type State = State;
91 type Style = ();
92
93 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
94 State {
95 ids: Ids::new(id_gen),
96 }
97 }
98
99 fn style(&self) -> Self::Style {}
100
101 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
102 common_base::prof_span!("Sound::update");
103 let widget::UpdateArgs { state, ui, .. } = args;
104
105 let mut events = Vec::new();
106
107 Rectangle::fill_with(args.rect.dim(), color::TRANSPARENT)
108 .xy(args.rect.xy())
109 .graphics_for(args.id)
110 .scroll_kids()
111 .scroll_kids_vertically()
112 .set(state.ids.window, ui);
113 Rectangle::fill_with([args.rect.w() / 2.0, args.rect.h()], color::TRANSPARENT)
114 .top_right()
115 .parent(state.ids.window)
116 .set(state.ids.window_r, ui);
117 Scrollbar::y_axis(state.ids.window)
118 .thickness(5.0)
119 .rgba(0.33, 0.33, 0.33, 1.0)
120 .set(state.ids.window_scrollbar, ui);
121
122 let non_master_volume_text_color =
123 match self.global_state.settings.audio.master_volume.muted {
124 true => TEXT_COLOR_GREY,
125 false => TEXT_COLOR,
126 };
127
128 Text::new(&self.localized_strings.get_msg("hud-settings-master_volume"))
130 .top_left_with_margins_on(state.ids.window, 10.0, 10.0)
131 .font_size(self.fonts.cyri.scale(14))
132 .font_id(self.fonts.cyri.conrod_id)
133 .color(TEXT_COLOR)
134 .set(state.ids.master_volume_text, ui);
135 let master_muted = ToggleButton::new(
137 self.global_state.settings.audio.master_volume.muted,
138 self.imgs.button_mute,
139 self.imgs.button_muted,
140 )
141 .w_h(24.0, 25.0)
142 .down_from(state.ids.master_volume_text, 10.0)
143 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
144 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
145 .set(state.ids.master_volume_muted, ui);
146 if master_muted != self.global_state.settings.audio.master_volume.muted {
147 events.push(MuteMasterVolume(master_muted));
148 }
149 if let Some(new_val) = ImageSlider::continuous(
151 self.global_state.settings.audio.master_volume.volume,
152 0.0,
153 1.0,
154 self.imgs.slider_indicator,
155 self.imgs.slider,
156 )
157 .w_h(104.0, 22.0)
158 .right_from(state.ids.master_volume_muted, 8.0)
159 .track_breadth(12.0)
160 .slider_length(10.0)
161 .pad_track((5.0, 5.0))
162 .set(state.ids.master_volume_slider, ui)
163 {
164 events.push(AdjustMasterVolume(new_val));
165 }
166 Text::new(&format!(
168 "{:2.0}%",
169 self.global_state.settings.audio.master_volume.volume * 100.0
170 ))
171 .right_from(state.ids.master_volume_slider, 8.0)
172 .font_size(self.fonts.cyri.scale(14))
173 .font_id(self.fonts.cyri.conrod_id)
174 .color(TEXT_COLOR)
175 .set(state.ids.master_volume_number, ui);
176
177 Text::new(
179 &self
180 .localized_strings
181 .get_msg("hud-settings-inactive_master_volume_perc"),
182 )
183 .down_from(state.ids.master_volume_muted, 10.0)
184 .font_size(self.fonts.cyri.scale(14))
185 .font_id(self.fonts.cyri.conrod_id)
186 .color(TEXT_COLOR)
187 .set(state.ids.inactive_master_volume_text, ui);
188 let inactive_master_muted = ToggleButton::new(
190 self.global_state
191 .settings
192 .audio
193 .inactive_master_volume_perc
194 .muted,
195 self.imgs.button_mute,
196 self.imgs.button_muted,
197 )
198 .w_h(24.0, 25.0)
199 .down_from(state.ids.inactive_master_volume_text, 10.0)
200 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
201 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
202 .set(state.ids.inactive_master_volume_muted, ui);
203 if inactive_master_muted
204 != self
205 .global_state
206 .settings
207 .audio
208 .inactive_master_volume_perc
209 .muted
210 {
211 events.push(MuteInactiveMasterVolume(inactive_master_muted));
212 }
213 if let Some(new_val) = ImageSlider::continuous(
215 self.global_state
216 .settings
217 .audio
218 .inactive_master_volume_perc
219 .volume,
220 0.0,
221 1.0,
222 self.imgs.slider_indicator,
223 self.imgs.slider,
224 )
225 .w_h(104.0, 22.0)
226 .right_from(state.ids.inactive_master_volume_muted, 8.0)
227 .track_breadth(12.0)
228 .slider_length(10.0)
229 .pad_track((5.0, 5.0))
230 .set(state.ids.inactive_master_volume_slider, ui)
231 {
232 events.push(AdjustInactiveMasterVolume(new_val));
233 }
234 Text::new(&format!(
236 "{:2.0}%",
237 self.global_state
238 .settings
239 .audio
240 .inactive_master_volume_perc
241 .volume
242 * 100.0
243 ))
244 .right_from(state.ids.inactive_master_volume_slider, 8.0)
245 .font_size(self.fonts.cyri.scale(14))
246 .font_id(self.fonts.cyri.conrod_id)
247 .color(non_master_volume_text_color)
248 .set(state.ids.inactive_master_volume_number, ui);
249
250 Text::new(&self.localized_strings.get_msg("hud-settings-music_volume"))
252 .down_from(state.ids.inactive_master_volume_muted, 10.0)
253 .font_size(self.fonts.cyri.scale(14))
254 .font_id(self.fonts.cyri.conrod_id)
255 .color(TEXT_COLOR)
256 .set(state.ids.music_volume_text, ui);
257 let music_muted = ToggleButton::new(
259 self.global_state.settings.audio.music_volume.muted,
260 self.imgs.button_mute,
261 self.imgs.button_muted,
262 )
263 .w_h(24.0, 25.0)
264 .down_from(state.ids.music_volume_text, 10.0)
265 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
266 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
267 .set(state.ids.music_volume_muted, ui);
268 if music_muted != self.global_state.settings.audio.music_volume.muted {
269 events.push(MuteMusicVolume(music_muted));
270 }
271 if let Some(new_val) = ImageSlider::continuous(
273 self.global_state.settings.audio.music_volume.volume,
274 0.0,
275 1.0,
276 self.imgs.slider_indicator,
277 self.imgs.slider,
278 )
279 .w_h(104.0, 22.0)
280 .right_from(state.ids.music_volume_muted, 8.0)
281 .track_breadth(12.0)
282 .slider_length(10.0)
283 .pad_track((5.0, 5.0))
284 .set(state.ids.music_volume_slider, ui)
285 {
286 events.push(AdjustMusicVolume(new_val));
287 }
288 Text::new(&format!(
290 "{:2.0}%",
291 self.global_state.settings.audio.music_volume.volume * 100.0
292 ))
293 .right_from(state.ids.music_volume_slider, 8.0)
294 .font_size(self.fonts.cyri.scale(14))
295 .font_id(self.fonts.cyri.conrod_id)
296 .color(non_master_volume_text_color)
297 .set(state.ids.music_volume_number, ui);
298
299 Text::new(
301 &self
302 .localized_strings
303 .get_msg("hud-settings-sound_effect_volume"),
304 )
305 .down_from(state.ids.music_volume_muted, 10.0)
306 .font_size(self.fonts.cyri.scale(14))
307 .font_id(self.fonts.cyri.conrod_id)
308 .color(TEXT_COLOR)
309 .set(state.ids.sfx_volume_text, ui);
310 let sfx_muted = ToggleButton::new(
312 self.global_state.settings.audio.sfx_volume.muted,
313 self.imgs.button_mute,
314 self.imgs.button_muted,
315 )
316 .w_h(24.0, 25.0)
317 .down_from(state.ids.sfx_volume_text, 10.0)
318 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
319 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
320 .set(state.ids.sfx_volume_muted, ui);
321 if sfx_muted != self.global_state.settings.audio.sfx_volume.muted {
322 events.push(MuteSfxVolume(sfx_muted));
323 }
324 if let Some(new_val) = ImageSlider::continuous(
326 self.global_state.settings.audio.sfx_volume.volume,
327 0.0,
328 1.0,
329 self.imgs.slider_indicator,
330 self.imgs.slider,
331 )
332 .w_h(104.0, 22.0)
333 .right_from(state.ids.sfx_volume_muted, 8.0)
334 .track_breadth(12.0)
335 .slider_length(10.0)
336 .pad_track((5.0, 5.0))
337 .set(state.ids.sfx_volume_slider, ui)
338 {
339 events.push(AdjustSfxVolume(new_val));
340 }
341 Text::new(&format!(
343 "{:2.0}%",
344 self.global_state.settings.audio.sfx_volume.volume * 100.0
345 ))
346 .right_from(state.ids.sfx_volume_slider, 8.0)
347 .font_size(self.fonts.cyri.scale(14))
348 .font_id(self.fonts.cyri.conrod_id)
349 .color(non_master_volume_text_color)
350 .set(state.ids.sfx_volume_number, ui);
351
352 Text::new(
354 &self
355 .localized_strings
356 .get_msg("hud-settings-ambience_volume"),
357 )
358 .down_from(state.ids.sfx_volume_muted, 10.0)
359 .font_size(self.fonts.cyri.scale(14))
360 .font_id(self.fonts.cyri.conrod_id)
361 .color(TEXT_COLOR)
362 .set(state.ids.ambience_volume_text, ui);
363 let ambience_muted = ToggleButton::new(
365 self.global_state.settings.audio.ambience_volume.muted,
366 self.imgs.button_mute,
367 self.imgs.button_muted,
368 )
369 .w_h(24.0, 25.0)
370 .down_from(state.ids.ambience_volume_text, 10.0)
371 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
372 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
373 .set(state.ids.ambience_volume_muted, ui);
374 if ambience_muted != self.global_state.settings.audio.ambience_volume.muted {
375 events.push(MuteAmbienceVolume(ambience_muted));
376 }
377 if let Some(new_val) = ImageSlider::continuous(
379 self.global_state.settings.audio.ambience_volume.volume,
380 0.0,
381 1.0,
382 self.imgs.slider_indicator,
383 self.imgs.slider,
384 )
385 .w_h(104.0, 22.0)
386 .right_from(state.ids.ambience_volume_muted, 8.0)
387 .track_breadth(12.0)
388 .slider_length(10.0)
389 .pad_track((5.0, 5.0))
390 .set(state.ids.ambience_volume_slider, ui)
391 {
392 events.push(AdjustAmbienceVolume(new_val));
393 }
394 Text::new(&format!(
396 "{:2.0}%",
397 self.global_state.settings.audio.ambience_volume.volume * 100.0
398 ))
399 .right_from(state.ids.ambience_volume_slider, 8.0)
400 .font_size(self.fonts.cyri.scale(14))
401 .font_id(self.fonts.cyri.conrod_id)
402 .color(non_master_volume_text_color)
403 .set(state.ids.ambience_volume_number, ui);
404
405 Text::new(&self.localized_strings.get_msg("hud-settings-rain_ambience"))
407 .font_size(self.fonts.cyri.scale(14))
408 .font_id(self.fonts.cyri.conrod_id)
409 .right_from(state.ids.rain_ambience_checkbox, 10.0)
410 .color(TEXT_COLOR)
411 .set(state.ids.rain_ambience_label, ui);
412
413 let rain_ambience_enabled = ToggleButton::new(
414 self.global_state.settings.audio.rain_ambience_enabled,
415 self.imgs.checkbox,
416 self.imgs.checkbox_checked,
417 )
418 .w_h(18.0, 18.0)
419 .down_from(state.ids.ambience_volume_muted, 10.0)
420 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
421 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
422 .set(state.ids.rain_ambience_checkbox, ui);
423
424 if self.global_state.settings.audio.rain_ambience_enabled != rain_ambience_enabled {
425 events.push(RainAmbience(rain_ambience_enabled));
426 }
427
428 Text::new(&self.localized_strings.get_msg("hud-settings-music_spacing"))
430 .down_from(state.ids.rain_ambience_checkbox, 10.0)
431 .font_size(self.fonts.cyri.scale(14))
432 .font_id(self.fonts.cyri.conrod_id)
433 .color(TEXT_COLOR)
434 .set(state.ids.music_spacing_text, ui);
435 if let Some(new_val) = ImageSlider::continuous(
437 self.global_state.settings.audio.music_spacing,
438 0.0,
439 2.0,
440 self.imgs.slider_indicator,
441 self.imgs.slider,
442 )
443 .w_h(104.0, 22.0)
444 .down_from(state.ids.music_spacing_text, 10.0)
445 .x_align_to(state.ids.ambience_volume_slider, Align::Start)
446 .track_breadth(12.0)
447 .slider_length(10.0)
448 .pad_track((5.0, 5.0))
449 .set(state.ids.music_spacing_slider, ui)
450 {
451 events.push(AdjustMusicSpacing(new_val));
452 }
453 Text::new(&format!(
455 "{:1.2}x",
456 self.global_state.settings.audio.music_spacing
457 ))
458 .right_from(state.ids.music_spacing_slider, 8.0)
459 .font_size(self.fonts.cyri.scale(14))
460 .font_id(self.fonts.cyri.conrod_id)
461 .color(TEXT_COLOR)
462 .set(state.ids.music_spacing_number, ui);
463
464 Text::new(&self.localized_strings.get_msg("hud-settings-sfx_channels"))
467 .down_from(state.ids.music_spacing_number, 10.0)
468 .x_align_to(state.ids.music_spacing_text, Align::Start)
469 .font_size(self.fonts.cyri.scale(14))
470 .font_id(self.fonts.cyri.conrod_id)
471 .color(TEXT_COLOR)
472 .set(state.ids.sfx_channels_label, ui);
473
474 let current: Option<usize> = match self.global_state.settings.audio.num_sfx_channels {
475 16 => Some(0),
476 32 => Some(1),
477 64 => Some(2),
478 _ => None,
479 };
480
481 let num_sfx_setting_list = [
482 SfxChannelSettings::Low.to_string(),
483 SfxChannelSettings::Medium.to_string(),
484 SfxChannelSettings::High.to_string(),
485 ];
486
487 let num_sfx_setting_list_shown = vec![
488 format!(
489 "{} ({})",
490 &self
491 .localized_strings
492 .get_msg("hud-settings-sfx_channels_low"),
493 &SfxChannelSettings::Low.to_usize().to_string()
494 ),
495 format!(
496 "{} ({})",
497 &self
498 .localized_strings
499 .get_msg("hud-settings-sfx_channels_med"),
500 &SfxChannelSettings::Medium.to_usize().to_string()
501 ),
502 format!(
503 "{} ({})",
504 &self
505 .localized_strings
506 .get_msg("hud-settings-sfx_channels_high"),
507 &SfxChannelSettings::High.to_usize().to_string()
508 ),
509 ];
510
511 if let Some(clicked) = DropDownList::new(&num_sfx_setting_list_shown, current)
512 .w_h(150.0, 22.0)
513 .color(MENU_BG)
514 .label_color(TEXT_COLOR)
515 .label_font_id(self.fonts.cyri.conrod_id)
516 .down_from(state.ids.sfx_channels_label, 10.0)
517 .set(state.ids.sfx_channels_list, ui)
518 {
519 let new_val = &num_sfx_setting_list[clicked];
520
521 events.push(SetNumSfxChannels(SfxChannelSettings::from_str_slice(
522 new_val,
523 )));
524 }
525
526 if Button::image(self.imgs.button)
578 .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
579 .hover_image(self.imgs.button_hover)
580 .press_image(self.imgs.button_press)
581 .down_from(state.ids.sfx_channels_list, 12.0)
582 .x_align_to(state.ids.ambience_volume_text, Align::Start)
583 .label(&self.localized_strings.get_msg("hud-settings-reset_sound"))
584 .label_font_size(self.fonts.cyri.scale(14))
585 .label_color(TEXT_COLOR)
586 .label_font_id(self.fonts.cyri.conrod_id)
587 .label_y(Relative::Scalar(2.0))
588 .set(state.ids.reset_sound_button, ui)
589 .was_clicked()
590 {
591 events.push(ResetAudioSettings);
592 }
593
594 events
595 }
596}