use super::{ img_ids::Imgs, BarNumbers, CrosshairType, Intro, PressBehavior, ShortcutNumbers, Show, XpBar, MENU_BG, TEXT_COLOR, }; use crate::{ i18n::{list_localizations, LanguageMetadata, VoxygenLocalization}, render::{AaMode, CloudMode, FluidMode}, ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton}, window::GameInput, GlobalState, }; use conrod_core::{ color, position::Relative, widget::{self, Button, DropDownList, Image, Rectangle, Scrollbar, Text}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; const FPS_CHOICES: [u32; 11] = [15, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500]; widget_ids! { struct Ids { settings_content, settings_content_r, settings_icon, settings_button_mo, settings_close, settings_title, settings_r, settings_l, settings_scrollbar, controls_texts[], controls_buttons[], controls_alignment_rectangle, button_help, button_help2, show_help_label, ui_scale_label, ui_scale_slider, ui_scale_button, ui_scale_value, relative_to_win_button, relative_to_win_text, absolute_scale_button, absolute_scale_text, gameplay, controls, languages, languages_list, rectangle, general_txt, debug_button, debug_button_label, tips_button, tips_button_label, interface, language_text, mouse_pan_slider, mouse_pan_label, mouse_pan_value, mouse_zoom_slider, mouse_zoom_label, mouse_zoom_value, mouse_zoom_invert_button, mouse_zoom_invert_label, mouse_y_invert_button, mouse_y_invert_label, smooth_pan_toggle_button, smooth_pan_toggle_label, ch_title, ch_transp_slider, ch_transp_label, ch_transp_value, ch_transp_text, ch_1_bg, ch_2_bg, ch_3_bg, crosshair_outer_1, crosshair_inner_1, crosshair_outer_2, crosshair_inner_2, crosshair_outer_3, crosshair_inner_3, settings_bg, sound, test, video, vd_slider, vd_text, vd_value, sprite_dist_slider, sprite_dist_text, sprite_dist_value, figure_dist_slider, figure_dist_text, figure_dist_value, max_fps_slider, max_fps_text, max_fps_value, fov_slider, fov_text, fov_value, gamma_slider, gamma_text, gamma_value, aa_mode_text, aa_mode_list, cloud_mode_text, cloud_mode_list, fluid_mode_text, fluid_mode_list, fullscreen_button, fullscreen_label, save_window_size_button, audio_volume_slider, audio_volume_text, sfx_volume_slider, sfx_volume_text, audio_device_list, audio_device_text, hotbar_title, bar_numbers_title, show_bar_numbers_none_button, show_bar_numbers_none_text, show_bar_numbers_values_button, show_bar_numbers_values_text, show_bar_numbers_percentage_button, show_bar_numbers_percentage_text, show_shortcuts_button, show_shortcuts_text, show_xpbar_button, show_xpbar_text, show_bars_button, show_bars_text, placeholder, chat_transp_title, chat_transp_text, chat_transp_slider, sct_title, sct_show_text, sct_show_radio, sct_single_dmg_text, sct_single_dmg_radio, sct_show_batch_text, sct_show_batch_radio, sct_batched_dmg_text, sct_batched_dmg_radio, sct_inc_dmg_text, sct_inc_dmg_radio, sct_batch_inc_text, sct_batch_inc_radio, sct_num_dur_text, sct_num_dur_slider, sct_num_dur_value, speech_bubble_dark_mode_text, speech_bubble_dark_mode_button, free_look_behavior_text, free_look_behavior_list } } pub enum SettingsTab { Interface, Video, Sound, Gameplay, Controls, } #[derive(WidgetCommon)] pub struct SettingsWindow<'a> { global_state: &'a GlobalState, show: &'a Show, imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, localized_strings: &'a std::sync::Arc, #[conrod(common_builder)] common: widget::CommonBuilder, } impl<'a> SettingsWindow<'a> { pub fn new( global_state: &'a GlobalState, show: &'a Show, imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, localized_strings: &'a std::sync::Arc, ) -> Self { Self { global_state, show, imgs, fonts, localized_strings, common: widget::CommonBuilder::default(), } } } pub struct State { ids: Ids, } pub enum Event { ToggleHelp, ToggleDebug, ToggleXpBar(XpBar), ToggleBarNumbers(BarNumbers), ToggleShortcutNumbers(ShortcutNumbers), ChangeTab(SettingsTab), Close, Intro(Intro), AdjustMousePan(u32), AdjustMouseZoom(u32), ToggleZoomInvert(bool), ToggleMouseYInvert(bool), ToggleSmoothPan(bool), AdjustViewDistance(u32), AdjustSpriteRenderDistance(u32), AdjustFigureLoDRenderDistance(u32), AdjustFOV(u16), AdjustGamma(f32), AdjustWindowSize([u16; 2]), ToggleFullscreen, ChangeAaMode(AaMode), ChangeCloudMode(CloudMode), ChangeFluidMode(FluidMode), AdjustMusicVolume(f32), AdjustSfxVolume(f32), ChangeAudioDevice(String), MaximumFPS(u32), CrosshairTransp(f32), CrosshairType(CrosshairType), UiScale(ScaleChange), ChatTransp(f32), Sct(bool), SctPlayerBatch(bool), SctDamageBatch(bool), SpeechBubbleDarkMode(bool), ChangeLanguage(LanguageMetadata), ChangeBinding(GameInput), ChangeFreeLookBehavior(PressBehavior), } pub enum ScaleChange { ToAbsolute, ToRelative, Adjust(f64), } impl<'a> Widget for SettingsWindow<'a> { type Event = Vec; type State = State; type Style = (); fn init_state(&self, id_gen: widget::id::Generator) -> Self::State { State { ids: Ids::new(id_gen), } } fn style(&self) -> Self::Style { () } fn update(self, args: widget::UpdateArgs) -> Self::Event { let widget::UpdateArgs { state, ui, .. } = args; let mut events = Vec::new(); let bar_values = self.global_state.settings.gameplay.bar_numbers; //let mut xp_bar = self.global_state.settings.gameplay.xp_bar; // Frame Alignment Rectangle::fill_with([824.0, 488.0], color::TRANSPARENT) .middle_of(ui.window) .set(state.ids.settings_bg, ui); // Frame Image::new(self.imgs.settings_frame_l) .top_left_with_margins_on(state.ids.settings_bg, 0.0, 0.0) .w_h(412.0, 488.0) .set(state.ids.settings_l, ui); Image::new(self.imgs.settings_frame_r) .right_from(state.ids.settings_l, 0.0) .parent(state.ids.settings_bg) .w_h(412.0, 488.0) .set(state.ids.settings_r, ui); // Content Alignment Rectangle::fill_with([198.0 * 4.0, 97.0 * 4.0], color::TRANSPARENT) .top_right_with_margins_on(state.ids.settings_r, 21.0 * 4.0, 4.0 * 4.0) .scroll_kids() .scroll_kids_vertically() .set(state.ids.settings_content, ui); Rectangle::fill_with([198.0 * 4.0 * 0.5, 97.0 * 4.0], color::TRANSPARENT) .top_right_with_margins_on(state.ids.settings_content, 0.0, 0.0) .parent(state.ids.settings_content) .set(state.ids.settings_content_r, ui); Scrollbar::y_axis(state.ids.settings_content) .thickness(5.0) .rgba(0.33, 0.33, 0.33, 1.0) .set(state.ids.settings_scrollbar, ui); // X-Button if Button::image(self.imgs.close_button) .w_h(28.0, 28.0) .hover_image(self.imgs.close_button_hover) .press_image(self.imgs.close_button_press) .top_right_with_margins_on(state.ids.settings_r, 0.0, 0.0) .set(state.ids.settings_close, ui) .was_clicked() { events.push(Event::Close); } // Title Text::new(&self.localized_strings.get("common.settings")) .mid_top_with_margin_on(state.ids.settings_bg, 5.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.settings_title, ui); // 1) Interface Tab ------------------------------- if Button::image(if let SettingsTab::Interface = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button }) .w_h(31.0 * 4.0, 12.0 * 4.0) .hover_image(if let SettingsTab::Interface = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_hover }) .press_image(if let SettingsTab::Interface = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_press }) .top_left_with_margins_on(state.ids.settings_l, 8.0 * 4.0, 2.0 * 4.0) .label(&self.localized_strings.get("common.interface")) .label_font_size(self.fonts.cyri.scale(14)) .label_font_id(self.fonts.cyri.conrod_id) .label_color(TEXT_COLOR) .set(state.ids.interface, ui) .was_clicked() { events.push(Event::ChangeTab(SettingsTab::Interface)); } // Contents Left Side if let SettingsTab::Interface = self.show.settings_tab { let crosshair_transp = self.global_state.settings.gameplay.crosshair_transp; let crosshair_type = self.global_state.settings.gameplay.crosshair_type; let ui_scale = self.global_state.settings.gameplay.ui_scale; let chat_transp = self.global_state.settings.gameplay.chat_transp; Text::new(&self.localized_strings.get("hud.settings.general")) .top_left_with_margins_on(state.ids.settings_content, 5.0, 5.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.general_txt, ui); // Help let show_help = ToggleButton::new( self.show.help, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.general_txt, 20.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.button_help, ui); if self.show.help != show_help { events.push(Event::ToggleHelp); } Text::new(&self.localized_strings.get("hud.settings.help_window")) .right_from(state.ids.button_help, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.button_help) .color(TEXT_COLOR) .set(state.ids.show_help_label, ui); // Debug let show_debug = ToggleButton::new( self.show.debug, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.button_help, 8.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.debug_button, ui); if self.show.debug != show_debug { events.push(Event::ToggleDebug); } Text::new(&self.localized_strings.get("hud.settings.debug_info")) .right_from(state.ids.debug_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.debug_button) .color(TEXT_COLOR) .set(state.ids.debug_button_label, ui); // Tips if Button::image(match self.global_state.settings.gameplay.intro_show { Intro::Show => self.imgs.checkbox_checked, Intro::Never => self.imgs.checkbox, }) .w_h(20.0, 20.0) .down_from(state.ids.debug_button, 8.0) .hover_image(match self.global_state.settings.gameplay.intro_show { Intro::Show => self.imgs.checkbox_checked_mo, Intro::Never => self.imgs.checkbox_mo, }) .press_image(self.imgs.checkbox_press) .set(state.ids.tips_button, ui) .was_clicked() { match self.global_state.settings.gameplay.intro_show { Intro::Show => events.push(Event::Intro(Intro::Never)), Intro::Never => events.push(Event::Intro(Intro::Show)), } }; Text::new(&self.localized_strings.get("hud.settings.tips_on_startup")) .right_from(state.ids.tips_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.button_help) .color(TEXT_COLOR) .set(state.ids.tips_button_label, ui); // Ui Scale Text::new(&self.localized_strings.get("hud.settings.ui_scale")) .down_from(state.ids.tips_button, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.ui_scale_label, ui); // Relative Scaling Button let (check_img, check_mo_img, check_press_img, relative_selected) = match ui_scale { ScaleMode::RelativeToWindow(_) => ( self.imgs.check_checked, self.imgs.check_checked_mo, self.imgs.check_checked, true, ), ScaleMode::Absolute(_) | ScaleMode::DpiFactor => ( self.imgs.check, self.imgs.check_mo, self.imgs.check_press, false, ), }; if Button::image(check_img) .w_h(288.0 / 24.0, 288.0 / 24.0) .down_from(state.ids.ui_scale_label, 20.0) .hover_image(check_mo_img) .press_image(check_press_img) .set(state.ids.relative_to_win_button, ui) .was_clicked() && !relative_selected { events.push(Event::UiScale(ScaleChange::ToRelative)); } Text::new(self.localized_strings.get("hud.settings.relative_scaling")) .right_from(state.ids.relative_to_win_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.relative_to_win_button) .color(TEXT_COLOR) .set(state.ids.relative_to_win_text, ui); // Absolute Scaling Button let (check_img, check_mo_img, check_press_img, absolute_selected) = match ui_scale { ScaleMode::Absolute(_) => ( self.imgs.check_checked, self.imgs.check_checked_mo, self.imgs.check_checked, true, ), ScaleMode::RelativeToWindow(_) | ScaleMode::DpiFactor => ( self.imgs.check, self.imgs.check_mo, self.imgs.check_press, false, ), }; if Button::image(check_img) .w_h(288.0 / 24.0, 288.0 / 24.0) .down_from(state.ids.relative_to_win_button, 8.0) .hover_image(check_mo_img) .press_image(check_press_img) .set(state.ids.absolute_scale_button, ui) .was_clicked() && !absolute_selected { events.push(Event::UiScale(ScaleChange::ToAbsolute)); } Text::new(self.localized_strings.get("hud.settings.custom_scaling")) .right_from(state.ids.absolute_scale_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.absolute_scale_button) .color(TEXT_COLOR) .set(state.ids.absolute_scale_text, ui); // Slider -> Inactive when "Relative to window" is selected if let ScaleMode::Absolute(scale) = ui_scale { if let Some(new_val) = ImageSlider::continuous( scale.log(2.0), 0.5f64.log(2.0), 1.0f64.log(2.0), self.imgs.slider_indicator, self.imgs.slider, ) .w_h(208.0, 22.0) .right_from(state.ids.absolute_scale_text, 12.0) .track_breadth(30.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.ui_scale_slider, ui) { events.push(Event::UiScale(ScaleChange::Adjust(2.0f64.powf(new_val)))); } // Custom Scaling Text Text::new(&format!("{:.2}", scale)) .right_from(state.ids.ui_scale_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.ui_scale_value, ui); } else { // Grey and unfunctional slider when Relative is selected ImageSlider::continuous(0.0, 0.0, 1.0, self.imgs.nothing, self.imgs.slider) .w_h(208.0, 22.0) .right_from(state.ids.absolute_scale_text, 10.0) .track_breadth(12.0) .slider_length(10.0) .track_color(Color::Rgba(1.0, 1.0, 1.0, 0.2)) .slider_color(Color::Rgba(1.0, 1.0, 1.0, 0.2)) .pad_track((5.0, 5.0)) .set(state.ids.ui_scale_slider, ui); } // Crosshair Options // Crosshair Types // Round if Button::image(if let CrosshairType::Round = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg }) .w_h(15.0 * 4.0, 15.0 * 4.0) .hover_image(if let CrosshairType::Round = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_hover }) .press_image(if let CrosshairType::Round = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_press }) .down_from(state.ids.ch_title, 20.0) .set(state.ids.ch_1_bg, ui) .was_clicked() { events.push(Event::CrosshairType(CrosshairType::Round)); } // Crosshair Image::new(self.imgs.crosshair_outer_round) .w_h(20.0 * 1.5, 20.0 * 1.5) .middle_of(state.ids.ch_1_bg) .color(Some(Color::Rgba( 1.0, 1.0, 1.0, self.global_state.settings.gameplay.crosshair_transp, ))) .graphics_for(state.ids.ch_1_bg) .set(state.ids.crosshair_outer_1, ui); Image::new(self.imgs.crosshair_inner) .w_h(21.0 * 2.0, 21.0 * 2.0) .middle_of(state.ids.crosshair_outer_1) .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6))) .graphics_for(state.ids.ch_1_bg) .set(state.ids.crosshair_inner_1, ui); // Rounded Edges if Button::image(if let CrosshairType::RoundEdges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg }) .w_h(15.0 * 4.0, 15.0 * 4.0) .hover_image(if let CrosshairType::RoundEdges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_hover }) .press_image(if let CrosshairType::RoundEdges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_press }) .right_from(state.ids.ch_1_bg, 20.0) .set(state.ids.ch_2_bg, ui) .was_clicked() { events.push(Event::CrosshairType(CrosshairType::RoundEdges)); } // Crosshair Image::new(self.imgs.crosshair_outer_round_edges) .w_h(21.0 * 1.5, 21.0 * 1.5) .middle_of(state.ids.ch_2_bg) .color(Some(Color::Rgba( 1.0, 1.0, 1.0, self.global_state.settings.gameplay.crosshair_transp, ))) .graphics_for(state.ids.ch_2_bg) .set(state.ids.crosshair_outer_2, ui); Image::new(self.imgs.crosshair_inner) .w_h(21.0 * 2.0, 21.0 * 2.0) .middle_of(state.ids.crosshair_outer_2) .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6))) .graphics_for(state.ids.ch_2_bg) .set(state.ids.crosshair_inner_2, ui); // Edges if Button::image(if let CrosshairType::Edges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg }) .w_h(15.0 * 4.0, 15.0 * 4.0) .hover_image(if let CrosshairType::Edges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_hover }) .press_image(if let CrosshairType::Edges = crosshair_type { self.imgs.crosshair_bg_pressed } else { self.imgs.crosshair_bg_press }) .right_from(state.ids.ch_2_bg, 20.0) .set(state.ids.ch_3_bg, ui) .was_clicked() { events.push(Event::CrosshairType(CrosshairType::Edges)); } // Crosshair Image::new(self.imgs.crosshair_outer_edges) .w_h(21.0 * 1.5, 21.0 * 1.5) .middle_of(state.ids.ch_3_bg) .color(Some(Color::Rgba( 1.0, 1.0, 1.0, self.global_state.settings.gameplay.crosshair_transp, ))) .graphics_for(state.ids.ch_3_bg) .set(state.ids.crosshair_outer_3, ui); Image::new(self.imgs.crosshair_inner) .w_h(21.0 * 2.0, 21.0 * 2.0) .middle_of(state.ids.crosshair_outer_3) .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6))) .graphics_for(state.ids.ch_3_bg) .set(state.ids.crosshair_inner_3, ui); // Crosshair Transparency Text and Slider Text::new(&self.localized_strings.get("hud.settings.crosshair")) .down_from(state.ids.absolute_scale_button, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.ch_title, ui); Text::new(&self.localized_strings.get("hud.settings.transparency")) .right_from(state.ids.ch_3_bg, 20.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.ch_transp_text, ui); if let Some(new_val) = ImageSlider::continuous( crosshair_transp, 0.0, 1.0, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.ch_transp_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.ch_transp_slider, ui) { events.push(Event::CrosshairTransp(new_val)); } Text::new(&format!("{:.2}", crosshair_transp,)) .right_from(state.ids.ch_transp_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .graphics_for(state.ids.ch_transp_slider) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.ch_transp_value, ui); // Hotbar text Text::new(&self.localized_strings.get("hud.settings.hotbar")) .down_from(state.ids.ch_1_bg, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.hotbar_title, ui); // Show xp bar if Button::image(match self.global_state.settings.gameplay.xp_bar { XpBar::Always => self.imgs.checkbox_checked, XpBar::OnGain => self.imgs.checkbox, }) .w_h(18.0, 18.0) .hover_image(match self.global_state.settings.gameplay.xp_bar { XpBar::Always => self.imgs.checkbox_checked_mo, XpBar::OnGain => self.imgs.checkbox_mo, }) .press_image(match self.global_state.settings.gameplay.xp_bar { XpBar::Always => self.imgs.checkbox_checked, XpBar::OnGain => self.imgs.checkbox_press, }) .down_from(state.ids.hotbar_title, 8.0) .set(state.ids.show_xpbar_button, ui) .was_clicked() { match self.global_state.settings.gameplay.xp_bar { XpBar::Always => events.push(Event::ToggleXpBar(XpBar::OnGain)), XpBar::OnGain => events.push(Event::ToggleXpBar(XpBar::Always)), } } Text::new( &self .localized_strings .get("hud.settings.toggle_bar_experience"), ) .right_from(state.ids.show_xpbar_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.show_xpbar_button) .color(TEXT_COLOR) .set(state.ids.show_xpbar_text, ui); // Show Shortcut Numbers if Button::image(match self.global_state.settings.gameplay.shortcut_numbers { ShortcutNumbers::On => self.imgs.checkbox_checked, ShortcutNumbers::Off => self.imgs.checkbox, }) .w_h(18.0, 18.0) .hover_image(match self.global_state.settings.gameplay.shortcut_numbers { ShortcutNumbers::On => self.imgs.checkbox_checked_mo, ShortcutNumbers::Off => self.imgs.checkbox_mo, }) .press_image(match self.global_state.settings.gameplay.shortcut_numbers { ShortcutNumbers::On => self.imgs.checkbox_checked, ShortcutNumbers::Off => self.imgs.checkbox_press, }) .down_from(state.ids.show_xpbar_button, 8.0) .set(state.ids.show_shortcuts_button, ui) .was_clicked() { match self.global_state.settings.gameplay.shortcut_numbers { ShortcutNumbers::On => { events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::Off)) }, ShortcutNumbers::Off => { events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::On)) }, } } Text::new(&self.localized_strings.get("hud.settings.toggle_shortcuts")) .right_from(state.ids.show_shortcuts_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.show_shortcuts_button) .color(TEXT_COLOR) .set(state.ids.show_shortcuts_text, ui); Rectangle::fill_with([60.0 * 4.0, 1.0 * 4.0], color::TRANSPARENT) .down_from(state.ids.show_shortcuts_text, 30.0) .set(state.ids.placeholder, ui); // Content Right Side /*Scrolling Combat text O Show Damage Numbers O Show single Damage Numbers O Show batched dealt Damage O Show incoming Damage O Batch incoming Numbers Number Display Duration: 1s ----I----5s */ // SCT/ Scrolling Combat Text Text::new( &self .localized_strings .get("hud.settings.scrolling_combat_text"), ) .top_left_with_margins_on(state.ids.settings_content_r, 5.0, 5.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.sct_title, ui); // Generally toggle the SCT let show_sct = ToggleButton::new( self.global_state.settings.gameplay.sct, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.sct_title, 20.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.sct_show_radio, ui); if self.global_state.settings.gameplay.sct != show_sct { events.push(Event::Sct(!self.global_state.settings.gameplay.sct)) } Text::new( &self .localized_strings .get("hud.settings.scrolling_combat_text"), ) .right_from(state.ids.sct_show_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.sct_show_radio) .color(TEXT_COLOR) .set(state.ids.sct_show_text, ui); if self.global_state.settings.gameplay.sct { // Toggle single damage numbers let show_sct_damage_batch = !ToggleButton::new( !self.global_state.settings.gameplay.sct_damage_batch, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.sct_show_text, 8.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.sct_single_dmg_radio, ui); Text::new( &self .localized_strings .get("hud.settings.single_damage_number"), ) .right_from(state.ids.sct_single_dmg_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.sct_single_dmg_radio) .color(TEXT_COLOR) .set(state.ids.sct_single_dmg_text, ui); // Toggle Batched Damage let show_sct_damage_batch = ToggleButton::new( show_sct_damage_batch, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.sct_single_dmg_radio, 8.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.sct_show_batch_radio, ui); if self.global_state.settings.gameplay.sct_damage_batch != show_sct_damage_batch { events.push(Event::SctDamageBatch( !self.global_state.settings.gameplay.sct_damage_batch, )) } Text::new(&self.localized_strings.get("hud.settings.cumulated_damage")) .right_from(state.ids.sct_show_batch_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.sct_batched_dmg_radio) .color(TEXT_COLOR) .set(state.ids.sct_show_batch_text, ui); // Toggle Incoming Damage let show_sct_player_batch = !ToggleButton::new( !self.global_state.settings.gameplay.sct_player_batch, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.sct_show_batch_radio, 8.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.sct_inc_dmg_radio, ui); Text::new(&self.localized_strings.get("hud.settings.incoming_damage")) .right_from(state.ids.sct_inc_dmg_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.sct_inc_dmg_radio) .color(TEXT_COLOR) .set(state.ids.sct_inc_dmg_text, ui); // Toggle Batched Incoming Damage let show_sct_player_batch = ToggleButton::new( show_sct_player_batch, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.sct_inc_dmg_radio, 8.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.sct_batch_inc_radio, ui); if self.global_state.settings.gameplay.sct_player_batch != show_sct_player_batch { events.push(Event::SctPlayerBatch( !self.global_state.settings.gameplay.sct_player_batch, )) } Text::new( &self .localized_strings .get("hud.settings.cumulated_incoming_damage"), ) .right_from(state.ids.sct_batch_inc_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.sct_batch_inc_radio) .color(TEXT_COLOR) .set(state.ids.sct_batch_inc_text, ui); } // Speech bubble dark mode let speech_bubble_dark_mode = ToggleButton::new( self.global_state.settings.gameplay.speech_bubble_dark_mode, self.imgs.checkbox, self.imgs.checkbox_checked, ) .down_from( if self.global_state.settings.gameplay.sct { state.ids.sct_batch_inc_radio } else { state.ids.sct_show_radio }, 20.0, ) .x(0.0) .w_h(18.0, 18.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.speech_bubble_dark_mode_button, ui); if self.global_state.settings.gameplay.speech_bubble_dark_mode != speech_bubble_dark_mode { events.push(Event::SpeechBubbleDarkMode(speech_bubble_dark_mode)); } Text::new( &self .localized_strings .get("hud.settings.speech_bubble_dark_mode"), ) .right_from(state.ids.speech_bubble_dark_mode_button, 10.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.speech_bubble_dark_mode_text, ui); // Energybars Numbers // Hotbar text Text::new(&self.localized_strings.get("hud.settings.energybar_numbers")) .down_from(state.ids.speech_bubble_dark_mode_button, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.bar_numbers_title, ui); // None if Button::image(if let BarNumbers::Off = bar_values { self.imgs.check_checked } else { self.imgs.check }) .w_h(288.0 / 24.0, 288.0 / 24.0) .hover_image(if let BarNumbers::Off = bar_values { self.imgs.check_checked_mo } else { self.imgs.check_mo }) .press_image(if let BarNumbers::Off = bar_values { self.imgs.check_checked } else { self.imgs.check_press }) .down_from(state.ids.bar_numbers_title, 8.0) .set(state.ids.show_bar_numbers_none_button, ui) .was_clicked() { events.push(Event::ToggleBarNumbers(BarNumbers::Off)) } Text::new(&self.localized_strings.get("hud.settings.none")) .right_from(state.ids.show_bar_numbers_none_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.show_bar_numbers_none_button) .color(TEXT_COLOR) .set(state.ids.show_bar_numbers_none_text, ui); // Values if Button::image(if let BarNumbers::Values = bar_values { self.imgs.check_checked } else { self.imgs.check }) .w_h(288.0 / 24.0, 288.0 / 24.0) .hover_image(if let BarNumbers::Values = bar_values { self.imgs.check_checked_mo } else { self.imgs.check_mo }) .press_image(if let BarNumbers::Values = bar_values { self.imgs.check_checked } else { self.imgs.check_press }) .down_from(state.ids.show_bar_numbers_none_button, 8.0) .set(state.ids.show_bar_numbers_values_button, ui) .was_clicked() { events.push(Event::ToggleBarNumbers(BarNumbers::Values)) } Text::new(&self.localized_strings.get("hud.settings.values")) .right_from(state.ids.show_bar_numbers_values_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.show_bar_numbers_values_button) .color(TEXT_COLOR) .set(state.ids.show_bar_numbers_values_text, ui); // Percentages if Button::image(if let BarNumbers::Percent = bar_values { self.imgs.check_checked } else { self.imgs.check }) .w_h(288.0 / 24.0, 288.0 / 24.0) .hover_image(if let BarNumbers::Percent = bar_values { self.imgs.check_checked_mo } else { self.imgs.check_mo }) .press_image(if let BarNumbers::Percent = bar_values { self.imgs.check_checked } else { self.imgs.check_press }) .down_from(state.ids.show_bar_numbers_values_button, 8.0) .set(state.ids.show_bar_numbers_percentage_button, ui) .was_clicked() { events.push(Event::ToggleBarNumbers(BarNumbers::Percent)) } Text::new(&self.localized_strings.get("hud.settings.percentages")) .right_from(state.ids.show_bar_numbers_percentage_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.show_bar_numbers_percentage_button) .color(TEXT_COLOR) .set(state.ids.show_bar_numbers_percentage_text, ui); // Chat Transp Text::new(&self.localized_strings.get("hud.settings.chat")) .down_from(state.ids.show_bar_numbers_percentage_button, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.chat_transp_title, ui); Text::new( &self .localized_strings .get("hud.settings.background_transparency"), ) .right_from(state.ids.chat_transp_slider, 20.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.chat_transp_text, ui); if let Some(new_val) = ImageSlider::continuous( chat_transp, 0.0, 0.9, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.chat_transp_title, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.chat_transp_slider, ui) { events.push(Event::ChatTransp(new_val)); } Text::new(&self.localized_strings.get("common.languages")) .down_from(state.ids.chat_transp_slider, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.language_text, ui); let selected_language = &self.global_state.settings.language.selected_language; let language_list = list_localizations(); let language_list_str: Vec = language_list .iter() .map(|e| e.language_name.clone()) .collect(); let selected = language_list .iter() .position(|x| x.language_identifier.contains(selected_language)); if let Some(clicked) = DropDownList::new(&language_list_str, selected) .down_from(state.ids.language_text, 8.0) .w_h(200.0, 22.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .set(state.ids.languages_list, ui) { events.push(Event::ChangeLanguage(language_list[clicked].to_owned())); } } // 2) Gameplay Tab -------------------------------- if Button::image(if let SettingsTab::Gameplay = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button }) .w_h(31.0 * 4.0, 12.0 * 4.0) .hover_image(if let SettingsTab::Gameplay = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_hover }) .press_image(if let SettingsTab::Gameplay = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_press }) .right_from(state.ids.interface, 0.0) .label(&self.localized_strings.get("common.gameplay")) .label_font_size(self.fonts.cyri.scale(14)) .label_font_id(self.fonts.cyri.conrod_id) .label_color(TEXT_COLOR) .set(state.ids.gameplay, ui) .was_clicked() { events.push(Event::ChangeTab(SettingsTab::Gameplay)); } // Contents if let SettingsTab::Gameplay = self.show.settings_tab { let display_pan = self.global_state.settings.gameplay.pan_sensitivity; let display_zoom = self.global_state.settings.gameplay.zoom_sensitivity; // Mouse Pan Sensitivity Text::new(&self.localized_strings.get("hud.settings.pan_sensitivity")) .top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.mouse_pan_label, ui); if let Some(new_val) = ImageSlider::discrete( display_pan, 1, 200, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(550.0, 22.0) .down_from(state.ids.mouse_pan_label, 10.0) .track_breadth(30.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.mouse_pan_slider, ui) { events.push(Event::AdjustMousePan(new_val)); } Text::new(&format!("{}", display_pan)) .right_from(state.ids.mouse_pan_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.mouse_pan_value, ui); // Mouse Zoom Sensitivity Text::new(&self.localized_strings.get("hud.settings.zoom_sensitivity")) .down_from(state.ids.mouse_pan_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.mouse_zoom_label, ui); if let Some(new_val) = ImageSlider::discrete( display_zoom, 1, 300, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(550.0, 22.0) .down_from(state.ids.mouse_zoom_label, 10.0) .track_breadth(30.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.mouse_zoom_slider, ui) { events.push(Event::AdjustMouseZoom(new_val)); } Text::new(&format!("{}", display_zoom)) .right_from(state.ids.mouse_zoom_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.mouse_zoom_value, ui); // Zoom Inversion let zoom_inverted = ToggleButton::new( self.global_state.settings.gameplay.zoom_inversion, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .down_from(state.ids.mouse_zoom_slider, 20.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.mouse_zoom_invert_button, ui); if self.global_state.settings.gameplay.zoom_inversion != zoom_inverted { events.push(Event::ToggleZoomInvert( !self.global_state.settings.gameplay.zoom_inversion, )); } Text::new( &self .localized_strings .get("hud.settings.invert_scroll_zoom"), ) .right_from(state.ids.mouse_zoom_invert_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.mouse_zoom_invert_button) .color(TEXT_COLOR) .set(state.ids.mouse_zoom_invert_label, ui); // Mouse Y Inversion let mouse_y_inverted = ToggleButton::new( self.global_state.settings.gameplay.mouse_y_inversion, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .right_from(state.ids.mouse_zoom_invert_label, 10.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.mouse_y_invert_button, ui); if self.global_state.settings.gameplay.mouse_y_inversion != mouse_y_inverted { events.push(Event::ToggleMouseYInvert( !self.global_state.settings.gameplay.mouse_y_inversion, )); } Text::new( &self .localized_strings .get("hud.settings.invert_mouse_y_axis"), ) .right_from(state.ids.mouse_y_invert_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.mouse_y_invert_button) .color(TEXT_COLOR) .set(state.ids.mouse_y_invert_label, ui); // Mouse Smoothing Toggle let smooth_pan_enabled = ToggleButton::new( self.global_state.settings.gameplay.smooth_pan_enable, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .right_from(state.ids.mouse_y_invert_label, 10.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.smooth_pan_toggle_button, ui); if self.global_state.settings.gameplay.smooth_pan_enable != smooth_pan_enabled { events.push(Event::ToggleSmoothPan( !self.global_state.settings.gameplay.smooth_pan_enable, )); } Text::new( &self .localized_strings .get("hud.settings.enable_mouse_smoothing"), ) .right_from(state.ids.smooth_pan_toggle_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .graphics_for(state.ids.smooth_pan_toggle_button) .color(TEXT_COLOR) .set(state.ids.smooth_pan_toggle_label, ui); // Free look behaviour Text::new( &self .localized_strings .get("hud.settings.free_look_behavior"), ) .down_from(state.ids.mouse_zoom_invert_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.free_look_behavior_text, ui); let mode_label_list = [ &self .localized_strings .get("hud.settings.press_behavior.toggle"), &self .localized_strings .get("hud.settings.press_behavior.hold"), ]; // Get which free look behavior is currently active let selected = self.global_state.settings.gameplay.free_look_behavior as usize; if let Some(clicked) = DropDownList::new(&mode_label_list, Some(selected)) .w_h(200.0, 30.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .down_from(state.ids.free_look_behavior_text, 8.0) .set(state.ids.free_look_behavior_list, ui) { match clicked { 0 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Toggle)), 1 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Hold)), _ => unreachable!(), } } } // 3) Controls Tab -------------------------------- if Button::image(if let SettingsTab::Controls = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button }) .w_h(31.0 * 4.0, 12.0 * 4.0) .hover_image(if let SettingsTab::Controls = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_hover }) .press_image(if let SettingsTab::Controls = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_press }) .right_from(state.ids.gameplay, 0.0) .label(&self.localized_strings.get("common.controls")) .label_font_size(self.fonts.cyri.scale(14)) .label_font_id(self.fonts.cyri.conrod_id) .label_color(TEXT_COLOR) .set(state.ids.controls, ui) .was_clicked() { events.push(Event::ChangeTab(SettingsTab::Controls)); } // Contents if let SettingsTab::Controls = self.show.settings_tab { let controls = &self.global_state.settings.controls; if controls.keybindings.len() > state.ids.controls_texts.len() || controls.keybindings.len() > state.ids.controls_buttons.len() { state.update(|s| { s.ids .controls_texts .resize(controls.keybindings.len(), &mut ui.widget_id_generator()); s.ids .controls_buttons .resize(controls.keybindings.len(), &mut ui.widget_id_generator()); }); } // Used for sequential placement in a flow-down pattern let mut previous_text_id = None; let mut keybindings_vec: Vec<&GameInput> = controls.keybindings.keys().collect(); keybindings_vec.sort(); // Loop all existing keybindings and the ids for text and button widgets for (game_input, (&text_id, &button_id)) in keybindings_vec.into_iter().zip( state .ids .controls_texts .iter() .zip(state.ids.controls_buttons.iter()), ) { if let Some(key) = controls.get_binding(*game_input) { let loc_key = self .localized_strings .get(game_input.get_localization_key()); let key_string = match self.global_state.window.remapping_keybindings { Some(game_input_binding) => { if *game_input == game_input_binding { String::from(self.localized_strings.get("hud.settings.awaitingkey")) } else { key.to_string() } }, None => key.to_string(), }; let text_widget = Text::new(loc_key) .color(TEXT_COLOR) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(18)); let button_widget = Button::new() .label(&key_string) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .label_font_size(self.fonts.cyri.scale(15)) .w(150.0) .rgba(0.0, 0.0, 0.0, 0.0) .border_rgba(0.0, 0.0, 0.0, 255.0) .label_y(Relative::Scalar(3.0)); // Place top-left if it's the first text, else under the previous one let text_widget = match previous_text_id { None => text_widget.top_left_with_margins_on( state.ids.settings_content, 10.0, 5.0, ), Some(prev_id) => text_widget.down_from(prev_id, 10.0), }; let text_width = text_widget.get_w(ui).unwrap_or(0.0); text_widget.set(text_id, ui); if button_widget .right_from(text_id, 350.0 - text_width) .set(button_id, ui) .was_clicked() { events.push(Event::ChangeBinding(*game_input)); } // Set the previous id to the current one for the next cycle previous_text_id = Some(text_id); } } // Add an empty text widget to simulate some bottom margin, because conrod sucks if let Some(prev_id) = previous_text_id { Rectangle::fill_with([1.0, 1.0], color::TRANSPARENT) .down_from(prev_id, 10.0) .set(state.ids.controls_alignment_rectangle, ui); } } // 4) Video Tab ----------------------------------- if Button::image(if let SettingsTab::Video = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button }) .w_h(31.0 * 4.0, 12.0 * 4.0) .hover_image(if let SettingsTab::Video = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_hover }) .press_image(if let SettingsTab::Video = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_press }) .right_from(state.ids.controls, 0.0) .label(&self.localized_strings.get("common.video")) .parent(state.ids.settings_r) .label_font_size(self.fonts.cyri.scale(14)) .label_font_id(self.fonts.cyri.conrod_id) .label_color(TEXT_COLOR) .set(state.ids.video, ui) .was_clicked() { events.push(Event::ChangeTab(SettingsTab::Video)); } // Contents if let SettingsTab::Video = self.show.settings_tab { // View Distance Text::new(&self.localized_strings.get("hud.settings.view_distance")) .top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.vd_text, ui); if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.view_distance, 1, 65, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.vd_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.vd_slider, ui) { events.push(Event::AdjustViewDistance(new_val)); } Text::new(&format!( "{}", self.global_state.settings.graphics.view_distance )) .right_from(state.ids.vd_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.vd_value, ui); // Max FPS Text::new(&self.localized_strings.get("hud.settings.maximum_fps")) .down_from(state.ids.vd_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.max_fps_text, ui); if let Some(which) = ImageSlider::discrete( FPS_CHOICES .iter() .position(|&x| x == self.global_state.settings.graphics.max_fps) .unwrap_or(5), 0, 10, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.max_fps_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.max_fps_slider, ui) { events.push(Event::MaximumFPS(FPS_CHOICES[which])); } Text::new(&format!("{}", self.global_state.settings.graphics.max_fps)) .right_from(state.ids.max_fps_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.max_fps_value, ui); // FOV Text::new(&self.localized_strings.get("hud.settings.fov")) .down_from(state.ids.max_fps_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.fov_text, ui); if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.fov, 30, 120, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.fov_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.fov_slider, ui) { events.push(Event::AdjustFOV(new_val)); } Text::new(&format!("{}", self.global_state.settings.graphics.fov)) .right_from(state.ids.fov_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.fov_value, ui); // Gamma Text::new(&self.localized_strings.get("hud.settings.gamma")) .down_from(state.ids.fov_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.gamma_text, ui); if let Some(new_val) = ImageSlider::discrete( (self.global_state.settings.graphics.gamma.log2() * 8.0).round() as i32, 8, -8, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.gamma_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.gamma_slider, ui) { events.push(Event::AdjustGamma(2.0f32.powf(new_val as f32 / 8.0))); } Text::new(&format!("{}", self.global_state.settings.graphics.gamma)) .right_from(state.ids.gamma_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.gamma_value, ui); // Sprites VD if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.sprite_render_distance, 50, 500, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .right_from(state.ids.vd_slider, 50.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.sprite_dist_slider, ui) { events.push(Event::AdjustSpriteRenderDistance(new_val)); } Text::new( &self .localized_strings .get("hud.settings.sprites_view_distance"), ) .up_from(state.ids.sprite_dist_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.sprite_dist_text, ui); Text::new(&format!( "{}", self.global_state.settings.graphics.sprite_render_distance )) .right_from(state.ids.sprite_dist_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.sprite_dist_value, ui); // Figure VD if let Some(new_val) = ImageSlider::discrete( self.global_state .settings .graphics .figure_lod_render_distance, 50, 500, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .right_from(state.ids.sprite_dist_slider, 50.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.figure_dist_slider, ui) { events.push(Event::AdjustFigureLoDRenderDistance(new_val)); } Text::new( &self .localized_strings .get("hud.settings.figures_view_distance"), ) .up_from(state.ids.figure_dist_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.figure_dist_text, ui); Text::new(&format!( "{}", self.global_state .settings .graphics .figure_lod_render_distance )) .right_from(state.ids.figure_dist_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.figure_dist_value, ui); // AaMode Text::new(&self.localized_strings.get("hud.settings.antialiasing_mode")) .down_from(state.ids.gamma_slider, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.aa_mode_text, ui); let mode_list = [ AaMode::None, AaMode::Fxaa, AaMode::MsaaX4, AaMode::MsaaX8, AaMode::MsaaX16, AaMode::SsaaX4, ]; let mode_label_list = [ "No AA", "FXAA", "MSAA x4", "MSAA x8", "MSAA x16 (experimental)", "SSAA x4", ]; // Get which AA mode is currently active let selected = mode_list .iter() .position(|x| *x == self.global_state.settings.graphics.aa_mode); if let Some(clicked) = DropDownList::new(&mode_label_list, selected) .w_h(400.0, 22.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .down_from(state.ids.aa_mode_text, 8.0) .set(state.ids.aa_mode_list, ui) { events.push(Event::ChangeAaMode(mode_list[clicked])); } // CloudMode Text::new( &self .localized_strings .get("hud.settings.cloud_rendering_mode"), ) .down_from(state.ids.aa_mode_list, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.cloud_mode_text, ui); let mode_list = [CloudMode::None, CloudMode::Regular]; let mode_label_list = [ &self.localized_strings.get("common.none"), &self .localized_strings .get("hud.settings.cloud_rendering_mode.regular"), ]; // Get which cloud rendering mode is currently active let selected = mode_list .iter() .position(|x| *x == self.global_state.settings.graphics.cloud_mode); if let Some(clicked) = DropDownList::new(&mode_label_list, selected) .w_h(400.0, 22.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .down_from(state.ids.cloud_mode_text, 8.0) .set(state.ids.cloud_mode_list, ui) { events.push(Event::ChangeCloudMode(mode_list[clicked])); } // FluidMode Text::new( &self .localized_strings .get("hud.settings.fluid_rendering_mode"), ) .down_from(state.ids.cloud_mode_list, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.fluid_mode_text, ui); let mode_list = [FluidMode::Cheap, FluidMode::Shiny]; let mode_label_list = [ &self .localized_strings .get("hud.settings.fluid_rendering_mode.cheap"), &self .localized_strings .get("hud.settings.fluid_rendering_mode.shiny"), ]; // Get which fluid rendering mode is currently active let selected = mode_list .iter() .position(|x| *x == self.global_state.settings.graphics.fluid_mode); if let Some(clicked) = DropDownList::new(&mode_label_list, selected) .w_h(400.0, 22.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .down_from(state.ids.fluid_mode_text, 8.0) .set(state.ids.fluid_mode_list, ui) { events.push(Event::ChangeFluidMode(mode_list[clicked])); } // Fullscreen Text::new(&self.localized_strings.get("hud.settings.fullscreen")) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .down_from(state.ids.fluid_mode_list, 8.0) .color(TEXT_COLOR) .set(state.ids.fullscreen_label, ui); let fullscreen = ToggleButton::new( self.global_state.settings.graphics.fullscreen, self.imgs.checkbox, self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) .right_from(state.ids.fullscreen_label, 10.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.fullscreen_button, ui); if self.global_state.settings.graphics.fullscreen != fullscreen { events.push(Event::ToggleFullscreen); } // Save current screen size if Button::image(self.imgs.settings_button) .w_h(31.0 * 5.0, 12.0 * 2.0) .hover_image(self.imgs.settings_button_hover) .press_image(self.imgs.settings_button_press) .down_from(state.ids.fullscreen_label, 12.0) .label(&self.localized_strings.get("hud.settings.save_window_size")) .label_font_size(self.fonts.cyri.scale(14)) .label_color(TEXT_COLOR) .label_font_id(self.fonts.cyri.conrod_id) .set(state.ids.save_window_size_button, ui) .was_clicked() { events.push(Event::AdjustWindowSize( self.global_state .window .logical_size() .map(|e| e as u16) .into_array(), )); } } // 5) Sound Tab ----------------------------------- if Button::image(if let SettingsTab::Sound = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button }) .w_h(31.0 * 4.0, 12.0 * 4.0) .hover_image(if let SettingsTab::Sound = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_hover }) .press_image(if let SettingsTab::Sound = self.show.settings_tab { self.imgs.settings_button_pressed } else { self.imgs.settings_button_press }) .right_from(state.ids.video, 0.0) .parent(state.ids.settings_r) .label(&self.localized_strings.get("common.sound")) .label_font_size(self.fonts.cyri.scale(14)) .label_font_id(self.fonts.cyri.conrod_id) .label_color(TEXT_COLOR) .set(state.ids.sound, ui) .was_clicked() { events.push(Event::ChangeTab(SettingsTab::Sound)); } // Contents if let SettingsTab::Sound = self.show.settings_tab { // Music Volume ----------------------------------------------------- Text::new(&self.localized_strings.get("hud.settings.music_volume")) .top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.audio_volume_text, ui); if let Some(new_val) = ImageSlider::continuous( self.global_state.settings.audio.music_volume, 0.0, 1.0, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.audio_volume_text, 10.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.audio_volume_slider, ui) { events.push(Event::AdjustMusicVolume(new_val)); } // SFX Volume ------------------------------------------------------- Text::new( &self .localized_strings .get("hud.settings.sound_effect_volume"), ) .down_from(state.ids.audio_volume_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.sfx_volume_text, ui); if let Some(new_val) = ImageSlider::continuous( self.global_state.settings.audio.sfx_volume, 0.0, 1.0, self.imgs.slider_indicator, self.imgs.slider, ) .w_h(104.0, 22.0) .down_from(state.ids.sfx_volume_text, 10.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) .set(state.ids.sfx_volume_slider, ui) { events.push(Event::AdjustSfxVolume(new_val)); } // Audio Device Selector -------------------------------------------- let device = &self.global_state.audio.device; let device_list = &self.global_state.audio.device_list; Text::new(&self.localized_strings.get("hud.settings.audio_device")) .down_from(state.ids.sfx_volume_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) .set(state.ids.audio_device_text, ui); // Get which device is currently selected let selected = device_list.iter().position(|x| x.contains(device)); if let Some(clicked) = DropDownList::new(&device_list, selected) .w_h(400.0, 22.0) .color(MENU_BG) .label_color(TEXT_COLOR) .label_font_id(self.fonts.opensans.conrod_id) .down_from(state.ids.audio_device_text, 10.0) .set(state.ids.audio_device_list, ui) { let new_val = device_list[clicked].clone(); events.push(Event::ChangeAudioDevice(new_val)); } } events } }