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 instrument_volume_text,
40 instrument_volume_slider,
41 instrument_volume_number,
42 instrument_volume_muted,
43 ambience_volume_text,
44 ambience_volume_slider,
45 ambience_volume_number,
46 ambience_volume_muted,
47 rain_ambience_label,
48 rain_ambience_checkbox,
49 indoor_ambience_label,
50 indoor_ambience_checkbox,
51 music_spacing_text,
52 music_spacing_slider,
53 music_spacing_number,
54 reset_sound_button,
55 combat_music_toggle_label,
56 combat_music_toggle_button,
57 sfx_channels_label,
58 sfx_channels_list,
59 }
62}
63
64#[derive(WidgetCommon)]
65pub struct Sound<'a> {
66 global_state: &'a GlobalState,
67 imgs: &'a Imgs,
68 fonts: &'a Fonts,
69 localized_strings: &'a Localization,
70 #[conrod(common_builder)]
71 common: widget::CommonBuilder,
72}
73impl<'a> Sound<'a> {
74 pub fn new(
75 global_state: &'a GlobalState,
76 imgs: &'a Imgs,
77 fonts: &'a Fonts,
78 localized_strings: &'a Localization,
79 ) -> Self {
80 Self {
81 global_state,
82 imgs,
83 fonts,
84 localized_strings,
85 common: widget::CommonBuilder::default(),
86 }
87 }
88}
89
90pub struct State {
91 ids: Ids,
92}
93
94impl Widget for Sound<'_> {
95 type Event = Vec<AudioChange>;
96 type State = State;
97 type Style = ();
98
99 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
100 State {
101 ids: Ids::new(id_gen),
102 }
103 }
104
105 fn style(&self) -> Self::Style {}
106
107 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
108 common_base::prof_span!("Sound::update");
109 let widget::UpdateArgs { state, ui, .. } = args;
110
111 let mut events = Vec::new();
112
113 Rectangle::fill_with(args.rect.dim(), color::TRANSPARENT)
114 .xy(args.rect.xy())
115 .graphics_for(args.id)
116 .scroll_kids()
117 .scroll_kids_vertically()
118 .set(state.ids.window, ui);
119 Rectangle::fill_with([args.rect.w() / 2.0, args.rect.h()], color::TRANSPARENT)
120 .top_right()
121 .parent(state.ids.window)
122 .set(state.ids.window_r, ui);
123 Scrollbar::y_axis(state.ids.window)
124 .thickness(5.0)
125 .rgba(0.33, 0.33, 0.33, 1.0)
126 .set(state.ids.window_scrollbar, ui);
127
128 let non_master_volume_text_color =
129 match self.global_state.settings.audio.master_volume.muted {
130 true => TEXT_COLOR_GREY,
131 false => TEXT_COLOR,
132 };
133
134 Text::new(&self.localized_strings.get_msg("hud-settings-master_volume"))
136 .top_left_with_margins_on(state.ids.window, 10.0, 10.0)
137 .font_size(self.fonts.cyri.scale(14))
138 .font_id(self.fonts.cyri.conrod_id)
139 .color(TEXT_COLOR)
140 .set(state.ids.master_volume_text, ui);
141 let master_muted = ToggleButton::new(
143 self.global_state.settings.audio.master_volume.muted,
144 self.imgs.button_mute,
145 self.imgs.button_muted,
146 )
147 .w_h(24.0, 25.0)
148 .down_from(state.ids.master_volume_text, 10.0)
149 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
150 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
151 .set(state.ids.master_volume_muted, ui);
152 if master_muted != self.global_state.settings.audio.master_volume.muted {
153 events.push(MuteMasterVolume(master_muted));
154 }
155 if let Some(new_val) = ImageSlider::continuous(
157 self.global_state.settings.audio.master_volume.volume,
158 0.0,
159 1.0,
160 self.imgs.slider_indicator,
161 self.imgs.slider,
162 )
163 .w_h(104.0, 22.0)
164 .right_from(state.ids.master_volume_muted, 8.0)
165 .track_breadth(12.0)
166 .slider_length(10.0)
167 .pad_track((5.0, 5.0))
168 .set(state.ids.master_volume_slider, ui)
169 {
170 events.push(AdjustMasterVolume(new_val));
171 }
172 Text::new(&format!(
174 "{:2.0}%",
175 self.global_state.settings.audio.master_volume.volume * 100.0
176 ))
177 .right_from(state.ids.master_volume_slider, 8.0)
178 .font_size(self.fonts.cyri.scale(14))
179 .font_id(self.fonts.cyri.conrod_id)
180 .color(TEXT_COLOR)
181 .set(state.ids.master_volume_number, ui);
182
183 Text::new(
185 &self
186 .localized_strings
187 .get_msg("hud-settings-inactive_master_volume_perc"),
188 )
189 .down_from(state.ids.master_volume_muted, 10.0)
190 .font_size(self.fonts.cyri.scale(14))
191 .font_id(self.fonts.cyri.conrod_id)
192 .color(TEXT_COLOR)
193 .set(state.ids.inactive_master_volume_text, ui);
194 let inactive_master_muted = ToggleButton::new(
196 self.global_state
197 .settings
198 .audio
199 .inactive_master_volume_perc
200 .muted,
201 self.imgs.button_mute,
202 self.imgs.button_muted,
203 )
204 .w_h(24.0, 25.0)
205 .down_from(state.ids.inactive_master_volume_text, 10.0)
206 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
207 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
208 .set(state.ids.inactive_master_volume_muted, ui);
209 if inactive_master_muted
210 != self
211 .global_state
212 .settings
213 .audio
214 .inactive_master_volume_perc
215 .muted
216 {
217 events.push(MuteInactiveMasterVolume(inactive_master_muted));
218 }
219 if let Some(new_val) = ImageSlider::continuous(
221 self.global_state
222 .settings
223 .audio
224 .inactive_master_volume_perc
225 .volume,
226 0.0,
227 1.0,
228 self.imgs.slider_indicator,
229 self.imgs.slider,
230 )
231 .w_h(104.0, 22.0)
232 .right_from(state.ids.inactive_master_volume_muted, 8.0)
233 .track_breadth(12.0)
234 .slider_length(10.0)
235 .pad_track((5.0, 5.0))
236 .set(state.ids.inactive_master_volume_slider, ui)
237 {
238 events.push(AdjustInactiveMasterVolume(new_val));
239 }
240 Text::new(&format!(
242 "{:2.0}%",
243 self.global_state
244 .settings
245 .audio
246 .inactive_master_volume_perc
247 .volume
248 * 100.0
249 ))
250 .right_from(state.ids.inactive_master_volume_slider, 8.0)
251 .font_size(self.fonts.cyri.scale(14))
252 .font_id(self.fonts.cyri.conrod_id)
253 .color(non_master_volume_text_color)
254 .set(state.ids.inactive_master_volume_number, ui);
255
256 Text::new(&self.localized_strings.get_msg("hud-settings-music_volume"))
258 .down_from(state.ids.inactive_master_volume_muted, 10.0)
259 .font_size(self.fonts.cyri.scale(14))
260 .font_id(self.fonts.cyri.conrod_id)
261 .color(TEXT_COLOR)
262 .set(state.ids.music_volume_text, ui);
263 let music_muted = ToggleButton::new(
265 self.global_state.settings.audio.music_volume.muted,
266 self.imgs.button_mute,
267 self.imgs.button_muted,
268 )
269 .w_h(24.0, 25.0)
270 .down_from(state.ids.music_volume_text, 10.0)
271 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
272 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
273 .set(state.ids.music_volume_muted, ui);
274 if music_muted != self.global_state.settings.audio.music_volume.muted {
275 events.push(MuteMusicVolume(music_muted));
276 }
277 if let Some(new_val) = ImageSlider::continuous(
279 self.global_state.settings.audio.music_volume.volume,
280 0.0,
281 1.0,
282 self.imgs.slider_indicator,
283 self.imgs.slider,
284 )
285 .w_h(104.0, 22.0)
286 .right_from(state.ids.music_volume_muted, 8.0)
287 .track_breadth(12.0)
288 .slider_length(10.0)
289 .pad_track((5.0, 5.0))
290 .set(state.ids.music_volume_slider, ui)
291 {
292 events.push(AdjustMusicVolume(new_val));
293 }
294 Text::new(&format!(
296 "{:2.0}%",
297 self.global_state.settings.audio.music_volume.volume * 100.0
298 ))
299 .right_from(state.ids.music_volume_slider, 8.0)
300 .font_size(self.fonts.cyri.scale(14))
301 .font_id(self.fonts.cyri.conrod_id)
302 .color(non_master_volume_text_color)
303 .set(state.ids.music_volume_number, ui);
304
305 Text::new(
307 &self
308 .localized_strings
309 .get_msg("hud-settings-sound_effect_volume"),
310 )
311 .down_from(state.ids.music_volume_muted, 10.0)
312 .font_size(self.fonts.cyri.scale(14))
313 .font_id(self.fonts.cyri.conrod_id)
314 .color(TEXT_COLOR)
315 .set(state.ids.sfx_volume_text, ui);
316 let sfx_muted = ToggleButton::new(
318 self.global_state.settings.audio.sfx_volume.muted,
319 self.imgs.button_mute,
320 self.imgs.button_muted,
321 )
322 .w_h(24.0, 25.0)
323 .down_from(state.ids.sfx_volume_text, 10.0)
324 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
325 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
326 .set(state.ids.sfx_volume_muted, ui);
327 if sfx_muted != self.global_state.settings.audio.sfx_volume.muted {
328 events.push(MuteSfxVolume(sfx_muted));
329 }
330 if let Some(new_val) = ImageSlider::continuous(
332 self.global_state.settings.audio.sfx_volume.volume,
333 0.0,
334 1.0,
335 self.imgs.slider_indicator,
336 self.imgs.slider,
337 )
338 .w_h(104.0, 22.0)
339 .right_from(state.ids.sfx_volume_muted, 8.0)
340 .track_breadth(12.0)
341 .slider_length(10.0)
342 .pad_track((5.0, 5.0))
343 .set(state.ids.sfx_volume_slider, ui)
344 {
345 events.push(AdjustSfxVolume(new_val));
346 }
347 Text::new(&format!(
349 "{:2.0}%",
350 self.global_state.settings.audio.sfx_volume.volume * 100.0
351 ))
352 .right_from(state.ids.sfx_volume_slider, 8.0)
353 .font_size(self.fonts.cyri.scale(14))
354 .font_id(self.fonts.cyri.conrod_id)
355 .color(non_master_volume_text_color)
356 .set(state.ids.sfx_volume_number, ui);
357
358 Text::new(
360 &self
361 .localized_strings
362 .get_msg("hud-settings-instrument_volume"),
363 )
364 .down_from(state.ids.sfx_volume_muted, 10.0)
365 .font_size(self.fonts.cyri.scale(14))
366 .font_id(self.fonts.cyri.conrod_id)
367 .color(TEXT_COLOR)
368 .set(state.ids.instrument_volume_text, ui);
369 let instrument_muted = ToggleButton::new(
371 self.global_state.settings.audio.instrument_volume.muted,
372 if sfx_muted {
373 self.imgs.button_muted
374 } else {
375 self.imgs.button_mute
376 },
377 self.imgs.button_muted,
378 )
379 .w_h(24.0, 25.0)
380 .down_from(state.ids.instrument_volume_text, 10.0)
381 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
382 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
383 .set(state.ids.instrument_volume_muted, ui);
384 if instrument_muted != self.global_state.settings.audio.instrument_volume.muted {
385 events.push(MuteInstrumentVolume(instrument_muted));
386 }
387 if let Some(new_val) = ImageSlider::continuous(
389 self.global_state.settings.audio.instrument_volume.volume,
390 0.0,
391 1.0,
392 self.imgs.slider_indicator,
393 self.imgs.slider,
394 )
395 .w_h(104.0, 22.0)
396 .right_from(state.ids.instrument_volume_muted, 8.0)
397 .track_breadth(12.0)
398 .slider_length(10.0)
399 .pad_track((5.0, 5.0))
400 .set(state.ids.instrument_volume_slider, ui)
401 {
402 events.push(AdjustInstrumentVolume(new_val));
403 }
404 Text::new(&format!(
406 "{:2.0}%",
407 self.global_state.settings.audio.instrument_volume.volume * 100.0
408 ))
409 .right_from(state.ids.instrument_volume_slider, 8.0)
410 .font_size(self.fonts.cyri.scale(14))
411 .font_id(self.fonts.cyri.conrod_id)
412 .color(non_master_volume_text_color)
413 .set(state.ids.instrument_volume_number, ui);
414
415 Text::new(
417 &self
418 .localized_strings
419 .get_msg("hud-settings-ambience_volume"),
420 )
421 .down_from(state.ids.instrument_volume_muted, 10.0)
422 .font_size(self.fonts.cyri.scale(14))
423 .font_id(self.fonts.cyri.conrod_id)
424 .color(TEXT_COLOR)
425 .set(state.ids.ambience_volume_text, ui);
426 let ambience_muted = ToggleButton::new(
428 self.global_state.settings.audio.ambience_volume.muted,
429 self.imgs.button_mute,
430 self.imgs.button_muted,
431 )
432 .w_h(24.0, 25.0)
433 .down_from(state.ids.ambience_volume_text, 10.0)
434 .hover_images(self.imgs.button_mute_hover, self.imgs.button_muted_hover)
435 .press_images(self.imgs.button_mute_press, self.imgs.button_muted_press)
436 .set(state.ids.ambience_volume_muted, ui);
437 if ambience_muted != self.global_state.settings.audio.ambience_volume.muted {
438 events.push(MuteAmbienceVolume(ambience_muted));
439 }
440 if let Some(new_val) = ImageSlider::continuous(
442 self.global_state.settings.audio.ambience_volume.volume,
443 0.0,
444 1.0,
445 self.imgs.slider_indicator,
446 self.imgs.slider,
447 )
448 .w_h(104.0, 22.0)
449 .right_from(state.ids.ambience_volume_muted, 8.0)
450 .track_breadth(12.0)
451 .slider_length(10.0)
452 .pad_track((5.0, 5.0))
453 .set(state.ids.ambience_volume_slider, ui)
454 {
455 events.push(AdjustAmbienceVolume(new_val));
456 }
457 Text::new(&format!(
459 "{:2.0}%",
460 self.global_state.settings.audio.ambience_volume.volume * 100.0
461 ))
462 .right_from(state.ids.ambience_volume_slider, 8.0)
463 .font_size(self.fonts.cyri.scale(14))
464 .font_id(self.fonts.cyri.conrod_id)
465 .color(non_master_volume_text_color)
466 .set(state.ids.ambience_volume_number, ui);
467
468 Text::new(&self.localized_strings.get_msg("hud-settings-rain_ambience"))
470 .font_size(self.fonts.cyri.scale(14))
471 .font_id(self.fonts.cyri.conrod_id)
472 .right_from(state.ids.rain_ambience_checkbox, 10.0)
473 .color(TEXT_COLOR)
474 .set(state.ids.rain_ambience_label, ui);
475
476 let rain_ambience_enabled = ToggleButton::new(
477 self.global_state.settings.audio.rain_ambience_enabled,
478 self.imgs.checkbox,
479 self.imgs.checkbox_checked,
480 )
481 .w_h(18.0, 18.0)
482 .down_from(state.ids.ambience_volume_muted, 10.0)
483 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
484 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
485 .set(state.ids.rain_ambience_checkbox, ui);
486
487 if self.global_state.settings.audio.rain_ambience_enabled != rain_ambience_enabled {
488 events.push(RainAmbience(rain_ambience_enabled));
489 }
490
491 Text::new(
493 &self
494 .localized_strings
495 .get_msg("hud-settings-indoor_ambience"),
496 )
497 .font_size(self.fonts.cyri.scale(14))
498 .font_id(self.fonts.cyri.conrod_id)
499 .right_from(state.ids.indoor_ambience_checkbox, 10.0)
500 .color(TEXT_COLOR)
501 .set(state.ids.indoor_ambience_label, ui);
502
503 let indoor_ambience_enabled = ToggleButton::new(
504 self.global_state.settings.audio.indoor_ambience_enabled,
505 self.imgs.checkbox,
506 self.imgs.checkbox_checked,
507 )
508 .w_h(18.0, 18.0)
509 .down_from(state.ids.rain_ambience_checkbox, 10.0)
510 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
511 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
512 .set(state.ids.indoor_ambience_checkbox, ui);
513
514 if self.global_state.settings.audio.indoor_ambience_enabled != indoor_ambience_enabled {
515 events.push(IndoorAmbience(indoor_ambience_enabled));
516 }
517
518 Text::new(&self.localized_strings.get_msg("hud-settings-music_spacing"))
520 .down_from(state.ids.indoor_ambience_checkbox, 10.0)
521 .font_size(self.fonts.cyri.scale(14))
522 .font_id(self.fonts.cyri.conrod_id)
523 .color(TEXT_COLOR)
524 .set(state.ids.music_spacing_text, ui);
525 if let Some(new_val) = ImageSlider::continuous(
527 self.global_state.settings.audio.music_spacing,
528 0.0,
529 2.0,
530 self.imgs.slider_indicator,
531 self.imgs.slider,
532 )
533 .w_h(104.0, 22.0)
534 .down_from(state.ids.music_spacing_text, 10.0)
535 .x_align_to(state.ids.ambience_volume_slider, Align::Start)
536 .track_breadth(12.0)
537 .slider_length(10.0)
538 .pad_track((5.0, 5.0))
539 .set(state.ids.music_spacing_slider, ui)
540 {
541 events.push(AdjustMusicSpacing(new_val));
542 }
543 Text::new(&format!(
545 "{:1.2}x",
546 self.global_state.settings.audio.music_spacing
547 ))
548 .right_from(state.ids.music_spacing_slider, 8.0)
549 .font_size(self.fonts.cyri.scale(14))
550 .font_id(self.fonts.cyri.conrod_id)
551 .color(TEXT_COLOR)
552 .set(state.ids.music_spacing_number, ui);
553
554 Text::new(&self.localized_strings.get_msg("hud-settings-sfx_channels"))
557 .down_from(state.ids.music_spacing_number, 10.0)
558 .x_align_to(state.ids.music_spacing_text, Align::Start)
559 .font_size(self.fonts.cyri.scale(14))
560 .font_id(self.fonts.cyri.conrod_id)
561 .color(TEXT_COLOR)
562 .set(state.ids.sfx_channels_label, ui);
563
564 let current: Option<usize> = match self.global_state.settings.audio.num_sfx_channels {
565 16 => Some(0),
566 32 => Some(1),
567 64 => Some(2),
568 _ => None,
569 };
570
571 let num_sfx_setting_list = [
572 SfxChannelSettings::Low.to_string(),
573 SfxChannelSettings::Medium.to_string(),
574 SfxChannelSettings::High.to_string(),
575 ];
576
577 let num_sfx_setting_list_shown = vec![
578 format!(
579 "{} ({})",
580 &self
581 .localized_strings
582 .get_msg("hud-settings-sfx_channels_low"),
583 &SfxChannelSettings::Low.to_usize().to_string()
584 ),
585 format!(
586 "{} ({})",
587 &self
588 .localized_strings
589 .get_msg("hud-settings-sfx_channels_med"),
590 &SfxChannelSettings::Medium.to_usize().to_string()
591 ),
592 format!(
593 "{} ({})",
594 &self
595 .localized_strings
596 .get_msg("hud-settings-sfx_channels_high"),
597 &SfxChannelSettings::High.to_usize().to_string()
598 ),
599 ];
600
601 if let Some(clicked) = DropDownList::new(&num_sfx_setting_list_shown, current)
602 .w_h(150.0, 22.0)
603 .color(MENU_BG)
604 .label_color(TEXT_COLOR)
605 .label_font_id(self.fonts.cyri.conrod_id)
606 .down_from(state.ids.sfx_channels_label, 10.0)
607 .set(state.ids.sfx_channels_list, ui)
608 {
609 let new_val = &num_sfx_setting_list[clicked];
610
611 events.push(SetNumSfxChannels(SfxChannelSettings::from_str_slice(
612 new_val,
613 )));
614 }
615
616 if Button::image(self.imgs.button)
668 .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
669 .hover_image(self.imgs.button_hover)
670 .press_image(self.imgs.button_press)
671 .down_from(state.ids.sfx_channels_list, 12.0)
672 .x_align_to(state.ids.ambience_volume_text, Align::Start)
673 .label(&self.localized_strings.get_msg("hud-settings-reset_sound"))
674 .label_font_size(self.fonts.cyri.scale(14))
675 .label_color(TEXT_COLOR)
676 .label_font_id(self.fonts.cyri.conrod_id)
677 .label_y(Relative::Scalar(2.0))
678 .set(state.ids.reset_sound_button, ui)
679 .was_clicked()
680 {
681 events.push(ResetAudioSettings);
682 }
683
684 events
685 }
686}