Skip to main content

veloren_voxygen/hud/settings_window/
interface.rs

1use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH, ScaleChange};
2
3use crate::{
4    GlobalState,
5    hud::{
6        BarNumbers, BuffPosition, CrosshairType, MENU_BG, ShortcutNumbers, TEXT_COLOR,
7        img_ids::Imgs,
8    },
9    session::settings_change::{Interface as InterfaceChange, Interface::*},
10    ui::{ImageSlider, ScaleMode, ToggleButton, fonts::Fonts},
11};
12use conrod_core::{
13    Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, color,
14    position::{Align, Relative},
15    widget::{self, Button, DropDownList, Image, Rectangle, Scrollbar, Text},
16    widget_ids,
17};
18use i18n::Localization;
19
20widget_ids! {
21    struct Ids{
22        window,
23        window_r,
24        window_scrollbar,
25        reset_interface_button,
26        ui_scale_label,
27        ui_scale_slider,
28        ui_scale_value,
29        ui_scale_list,
30        relative_to_win_button,
31        relative_to_win_text,
32        absolute_scale_button,
33        absolute_scale_text,
34        general_txt,
35        load_tips_button,
36        load_tips_button_label,
37        debug_button,
38        debug_button_label,
39        hitboxes_button,
40        hitboxes_button_label,
41        chat_button,
42        chat_button_label,
43        draggable_windows_button,
44        draggable_windows_button_label,
45        biome_change_popups_button,
46        biome_change_popups_button_label,
47        compact_item_slots_button,
48        compact_item_slots_button_label,
49        hotkey_hints_button,
50        hotkey_hints_button_label,
51        ch_title,
52        ch_transp_slider,
53        ch_transp_value,
54        ch_transp_text,
55        ch_1_bg,
56        ch_2_bg,
57        ch_3_bg,
58        crosshair_outer_1,
59        crosshair_inner_1,
60        crosshair_outer_2,
61        crosshair_inner_2,
62        crosshair_outer_3,
63        crosshair_inner_3,
64        row_background_opacity_text,
65        row_background_opacity_slider,
66        row_background_opacity_value_text,
67        pause_menu_overlay_opacity_text,
68        pause_menu_overlay_opacity_slider,
69        pause_menu_overlay_opacity_value_text,
70        //
71        hotbar_title,
72        bar_numbers_title,
73        show_bar_numbers_none_button,
74        show_bar_numbers_none_text,
75        show_bar_numbers_values_button,
76        show_bar_numbers_values_text,
77        show_bar_numbers_percentage_button,
78        show_bar_numbers_percentage_text,
79        always_show_bars_button,
80        always_show_bars_label,
81        enable_poise_bar_button,
82        enable_poise_bar_label,
83        use_health_prefixes_text,
84        use_health_prefixes_button,
85        //
86        show_shortcuts_button,
87        show_shortcuts_text,
88        buff_pos_bar_button,
89        buff_pos_bar_text,
90        buff_pos_map_button,
91        buff_pos_map_text,
92        //
93        slots_title,
94        slots_use_prefixes_text,
95        slots_use_prefixes_radio,
96        slots_prefix_switch_point_slider,
97        slots_prefix_switch_point_text,
98        slots_prefix_switch_point_value,
99        //
100        sct_title,
101        sct_show_text,
102        sct_show_radio,
103        sct_round_dmg_text,
104        sct_round_dmg_radio,
105        sct_dmg_accum_duration_slider,
106        sct_dmg_accum_duration_text,
107        sct_dmg_accum_duration_value,
108        sct_show_inc_dmg_text,
109        sct_show_inc_dmg_radio,
110        sct_inc_dmg_accum_duration_slider,
111        sct_inc_dmg_accum_duration_text,
112        sct_inc_dmg_accum_duration_value,
113        //
114        speech_bubble_text,
115        speech_bubble_self_text,
116        speech_bubble_self_button,
117        speech_bubble_dark_mode_text,
118        speech_bubble_dark_mode_button,
119        speech_bubble_icon_text,
120        speech_bubble_icon_button,
121        //
122        experience_numbers_title,
123        accum_experience_text,
124        accum_experience_button,
125        //
126        minimap_title,
127        minimap_scale_text,
128        minimap_scale_slider,
129        minimap_scale_value_text,
130        minimap_colored_player_marker_text,
131        minimap_colored_player_marker_button,
132    }
133}
134
135#[derive(WidgetCommon)]
136pub struct Interface<'a> {
137    global_state: &'a GlobalState,
138    imgs: &'a Imgs,
139    fonts: &'a Fonts,
140    localized_strings: &'a Localization,
141    #[conrod(common_builder)]
142    common: widget::CommonBuilder,
143}
144impl<'a> Interface<'a> {
145    pub fn new(
146        global_state: &'a GlobalState,
147        imgs: &'a Imgs,
148        fonts: &'a Fonts,
149        localized_strings: &'a Localization,
150    ) -> Self {
151        Self {
152            global_state,
153            imgs,
154            fonts,
155            localized_strings,
156            common: widget::CommonBuilder::default(),
157        }
158    }
159}
160
161pub struct State {
162    ids: Ids,
163}
164
165impl Widget for Interface<'_> {
166    type Event = Vec<InterfaceChange>;
167    type State = State;
168    type Style = ();
169
170    fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
171        State {
172            ids: Ids::new(id_gen),
173        }
174    }
175
176    fn style(&self) -> Self::Style {}
177
178    fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
179        common_base::prof_span!("Interface::update");
180        let widget::UpdateArgs { state, ui, .. } = args;
181
182        let mut events = Vec::new();
183
184        Rectangle::fill_with(args.rect.dim(), color::TRANSPARENT)
185            .xy(args.rect.xy())
186            .graphics_for(args.id)
187            .scroll_kids()
188            .scroll_kids_vertically()
189            .set(state.ids.window, ui);
190        Rectangle::fill_with([args.rect.w() / 2.0, args.rect.h()], color::TRANSPARENT)
191            .top_right()
192            .parent(state.ids.window)
193            .set(state.ids.window_r, ui);
194        Scrollbar::y_axis(state.ids.window)
195            .thickness(5.0)
196            .rgba(0.33, 0.33, 0.33, 1.0)
197            .set(state.ids.window_scrollbar, ui);
198
199        let bar_values = self.global_state.settings.interface.bar_numbers;
200        let crosshair_opacity = self.global_state.settings.interface.crosshair_opacity;
201        let crosshair_type = self.global_state.settings.interface.crosshair_type;
202        let ui_scale = self.global_state.settings.interface.ui_scale;
203        let row_opacity = self.global_state.settings.interface.row_background_opacity;
204        let pause_overlay_opacity = self
205            .global_state
206            .settings
207            .interface
208            .pause_menu_overlay_opacity;
209
210        Text::new(&self.localized_strings.get_msg("hud-settings-general"))
211            .top_left_with_margins_on(state.ids.window, 5.0, 5.0)
212            .font_size(self.fonts.cyri.scale(18))
213            .font_id(self.fonts.cyri.conrod_id)
214            .color(TEXT_COLOR)
215            .set(state.ids.general_txt, ui);
216
217        // Loading Screen Tips
218        let show_tips = ToggleButton::new(
219            self.global_state.settings.interface.loading_tips,
220            self.imgs.checkbox,
221            self.imgs.checkbox_checked,
222        )
223        .w_h(18.0, 18.0)
224        .down_from(state.ids.general_txt, 20.0)
225        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
226        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
227        .set(state.ids.load_tips_button, ui);
228
229        if self.global_state.settings.interface.loading_tips != show_tips {
230            events.push(ToggleTips(
231                !self.global_state.settings.interface.loading_tips,
232            ));
233        }
234
235        Text::new(&self.localized_strings.get_msg("hud-settings-loading_tips"))
236            .right_from(state.ids.load_tips_button, 10.0)
237            .font_size(self.fonts.cyri.scale(14))
238            .font_id(self.fonts.cyri.conrod_id)
239            .graphics_for(state.ids.load_tips_button)
240            .color(TEXT_COLOR)
241            .set(state.ids.load_tips_button_label, ui);
242
243        // Debug
244        let show_debug = ToggleButton::new(
245            self.global_state.settings.interface.toggle_debug,
246            self.imgs.checkbox,
247            self.imgs.checkbox_checked,
248        )
249        .w_h(18.0, 18.0)
250        .down_from(state.ids.load_tips_button, 8.0)
251        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
252        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
253        .set(state.ids.debug_button, ui);
254
255        if self.global_state.settings.interface.toggle_debug != show_debug {
256            events.push(ToggleDebug(show_debug));
257        }
258
259        Text::new(&self.localized_strings.get_msg("hud-settings-debug_info"))
260            .right_from(state.ids.debug_button, 10.0)
261            .font_size(self.fonts.cyri.scale(14))
262            .font_id(self.fonts.cyri.conrod_id)
263            .graphics_for(state.ids.debug_button)
264            .color(TEXT_COLOR)
265            .set(state.ids.debug_button_label, ui);
266
267        // Hitboxes
268        let show_hitboxes = ToggleButton::new(
269            self.global_state.settings.interface.toggle_hitboxes,
270            self.imgs.checkbox,
271            self.imgs.checkbox_checked,
272        )
273        .w_h(18.0, 18.0)
274        .down_from(state.ids.debug_button, 8.0)
275        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
276        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
277        .set(state.ids.hitboxes_button, ui);
278
279        if self.global_state.settings.interface.toggle_hitboxes != show_hitboxes {
280            events.push(ToggleHitboxes(show_hitboxes));
281        }
282
283        Text::new(&self.localized_strings.get_msg("hud-settings-show_hitboxes"))
284            .right_from(state.ids.hitboxes_button, 10.0)
285            .font_size(self.fonts.cyri.scale(14))
286            .font_id(self.fonts.cyri.conrod_id)
287            .graphics_for(state.ids.hitboxes_button)
288            .color(TEXT_COLOR)
289            .set(state.ids.hitboxes_button_label, ui);
290
291        // Chat
292        let show_chat = ToggleButton::new(
293            self.global_state.settings.interface.toggle_chat,
294            self.imgs.checkbox,
295            self.imgs.checkbox_checked,
296        )
297        .w_h(18.0, 18.0)
298        .down_from(state.ids.hitboxes_button, 8.0)
299        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
300        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
301        .set(state.ids.chat_button, ui);
302
303        if self.global_state.settings.interface.toggle_chat != show_chat {
304            events.push(ToggleChat(show_chat));
305        }
306
307        Text::new(&self.localized_strings.get_msg("hud-settings-show_chat"))
308            .right_from(state.ids.chat_button, 10.0)
309            .font_size(self.fonts.cyri.scale(14))
310            .font_id(self.fonts.cyri.conrod_id)
311            .graphics_for(state.ids.chat_button)
312            .color(TEXT_COLOR)
313            .set(state.ids.chat_button_label, ui);
314
315        // Draggable windows
316        let draggable_windows = ToggleButton::new(
317            self.global_state
318                .settings
319                .interface
320                .toggle_draggable_windows,
321            self.imgs.checkbox,
322            self.imgs.checkbox_checked,
323        )
324        .w_h(18.0, 18.0)
325        .down_from(state.ids.chat_button, 8.0)
326        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
327        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
328        .set(state.ids.draggable_windows_button, ui);
329
330        if self
331            .global_state
332            .settings
333            .interface
334            .toggle_draggable_windows
335            != draggable_windows
336        {
337            events.push(ToggleDraggableWindows(draggable_windows));
338        }
339
340        Text::new(
341            &self
342                .localized_strings
343                .get_msg("hud-settings-draggable_windows"),
344        )
345        .right_from(state.ids.draggable_windows_button, 10.0)
346        .font_size(self.fonts.cyri.scale(14))
347        .font_id(self.fonts.cyri.conrod_id)
348        .graphics_for(state.ids.draggable_windows_button)
349        .color(TEXT_COLOR)
350        .set(state.ids.draggable_windows_button_label, ui);
351
352        // Biome change popups
353        let biome_change_popups = ToggleButton::new(
354            self.global_state
355                .settings
356                .interface
357                .toggle_biome_change_popups,
358            self.imgs.checkbox,
359            self.imgs.checkbox_checked,
360        )
361        .w_h(18.0, 18.0)
362        .down_from(state.ids.draggable_windows_button, 8.0)
363        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
364        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
365        .set(state.ids.biome_change_popups_button, ui);
366
367        if self
368            .global_state
369            .settings
370            .interface
371            .toggle_biome_change_popups
372            != biome_change_popups
373        {
374            events.push(ToggleBiomeChangePopups(biome_change_popups));
375        }
376
377        Text::new(
378            &self
379                .localized_strings
380                .get_msg("hud-settings-biome_change_popups"),
381        )
382        .right_from(state.ids.biome_change_popups_button, 10.0)
383        .font_size(self.fonts.cyri.scale(14))
384        .font_id(self.fonts.cyri.conrod_id)
385        .graphics_for(state.ids.biome_change_popups_button)
386        .color(TEXT_COLOR)
387        .set(state.ids.biome_change_popups_button_label, ui);
388
389        // Toggle compact item slots
390        let compact_item_slots = ToggleButton::new(
391            self.global_state
392                .settings
393                .interface
394                .toggle_compact_item_slots,
395            self.imgs.checkbox,
396            self.imgs.checkbox_checked,
397        )
398        .w_h(18.0, 18.0)
399        .down_from(state.ids.biome_change_popups_button, 8.0)
400        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
401        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
402        .set(state.ids.compact_item_slots_button, ui);
403
404        if self
405            .global_state
406            .settings
407            .interface
408            .toggle_compact_item_slots
409            != compact_item_slots
410        {
411            events.push(ToggleCompactItemSlots(compact_item_slots));
412        }
413
414        Text::new(
415            &self
416                .localized_strings
417                .get_msg("hud-settings-compact_item_slots"),
418        )
419        .right_from(state.ids.compact_item_slots_button, 10.0)
420        .font_size(self.fonts.cyri.scale(14))
421        .font_id(self.fonts.cyri.conrod_id)
422        .graphics_for(state.ids.compact_item_slots_button)
423        .color(TEXT_COLOR)
424        .set(state.ids.compact_item_slots_button_label, ui);
425
426        // Hotkey hints
427        let show_hotkey_hints = ToggleButton::new(
428            self.global_state.settings.interface.toggle_hotkey_hints,
429            self.imgs.checkbox,
430            self.imgs.checkbox_checked,
431        )
432        .w_h(18.0, 18.0)
433        .down_from(state.ids.compact_item_slots_button, 8.0)
434        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
435        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
436        .set(state.ids.hotkey_hints_button, ui);
437
438        if self.global_state.settings.interface.toggle_hotkey_hints != show_hotkey_hints {
439            events.push(ToggleHotkeyHints(show_hotkey_hints));
440        }
441
442        Text::new(
443            &self
444                .localized_strings
445                .get_msg("hud-settings-show_hotkey_hints"),
446        )
447        .right_from(state.ids.hotkey_hints_button, 10.0)
448        .font_size(self.fonts.cyri.scale(14))
449        .font_id(self.fonts.cyri.conrod_id)
450        .graphics_for(state.ids.hotkey_hints_button)
451        .color(TEXT_COLOR)
452        .set(state.ids.hotkey_hints_button_label, ui);
453
454        // Row background opacity
455        Text::new(
456            &self
457                .localized_strings
458                .get_msg("hud-settings-row_background_opacity"),
459        )
460        .down_from(state.ids.hotkey_hints_button, 10.0)
461        .font_size(self.fonts.cyri.scale(14))
462        .font_id(self.fonts.cyri.conrod_id)
463        .color(TEXT_COLOR)
464        .set(state.ids.row_background_opacity_text, ui);
465
466        if let Some(new_opacity) = ImageSlider::continuous(
467            row_opacity,
468            0.0,
469            0.1,
470            self.imgs.slider_indicator,
471            self.imgs.slider,
472        )
473        .w_h(104.0, 22.0)
474        .down_from(state.ids.row_background_opacity_text, 8.0)
475        .track_breadth(12.0)
476        .slider_length(10.0)
477        .pad_track((5.0, 5.0))
478        .set(state.ids.row_background_opacity_slider, ui)
479        {
480            events.push(RowBackgroundOpacity(new_opacity));
481        }
482
483        Text::new(&format!("{:.3}", row_opacity))
484            .right_from(state.ids.row_background_opacity_slider, 8.0)
485            .font_size(self.fonts.cyri.scale(14))
486            .graphics_for(state.ids.row_background_opacity_slider)
487            .font_id(self.fonts.cyri.conrod_id)
488            .color(TEXT_COLOR)
489            .set(state.ids.row_background_opacity_value_text, ui);
490
491        // Pause menu overlay opacity
492        Text::new(
493            &self
494                .localized_strings
495                .get_msg("hud-settings-pause_menu_overlay_opacity"),
496        )
497        .down_from(state.ids.row_background_opacity_slider, 10.0)
498        .font_size(self.fonts.cyri.scale(14))
499        .font_id(self.fonts.cyri.conrod_id)
500        .color(TEXT_COLOR)
501        .set(state.ids.pause_menu_overlay_opacity_text, ui);
502
503        if let Some(new_opacity) = ImageSlider::continuous(
504            pause_overlay_opacity,
505            0.0,
506            1.0,
507            self.imgs.slider_indicator,
508            self.imgs.slider,
509        )
510        .w_h(104.0, 22.0)
511        .down_from(state.ids.pause_menu_overlay_opacity_text, 8.0)
512        .track_breadth(12.0)
513        .slider_length(10.0)
514        .pad_track((5.0, 5.0))
515        .set(state.ids.pause_menu_overlay_opacity_slider, ui)
516        {
517            events.push(PauseMenuOverlayOpacity(new_opacity));
518        }
519
520        Text::new(&format!("{:.3}", pause_overlay_opacity))
521            .right_from(state.ids.pause_menu_overlay_opacity_slider, 8.0)
522            .font_size(self.fonts.cyri.scale(14))
523            .graphics_for(state.ids.pause_menu_overlay_opacity_slider)
524            .font_id(self.fonts.cyri.conrod_id)
525            .color(TEXT_COLOR)
526            .set(state.ids.pause_menu_overlay_opacity_value_text, ui);
527
528        // Ui Scale
529        Text::new(&self.localized_strings.get_msg("hud-settings-ui_scale"))
530            .down_from(state.ids.pause_menu_overlay_opacity_slider, 10.0)
531            .font_size(self.fonts.cyri.scale(18))
532            .font_id(self.fonts.cyri.conrod_id)
533            .color(TEXT_COLOR)
534            .set(state.ids.ui_scale_label, ui);
535
536        // Relative Scaling Button
537        let (check_img, check_mo_img, check_press_img, relative_selected) = match ui_scale {
538            ScaleMode::RelativeToWindow(_) => (
539                self.imgs.check_checked,
540                self.imgs.check_checked_mo,
541                self.imgs.check_checked,
542                true,
543            ),
544            ScaleMode::Absolute(_) | ScaleMode::DpiFactor => (
545                self.imgs.check,
546                self.imgs.check_mo,
547                self.imgs.check_press,
548                false,
549            ),
550        };
551        if Button::image(check_img)
552            .w_h(12.0, 12.0)
553            .down_from(state.ids.ui_scale_label, 20.0)
554            .hover_image(check_mo_img)
555            .press_image(check_press_img)
556            .set(state.ids.relative_to_win_button, ui)
557            .was_clicked()
558            && !relative_selected
559        {
560            events.push(UiScale(ScaleChange::ToRelative));
561        }
562
563        Text::new(
564            &self
565                .localized_strings
566                .get_msg("hud-settings-relative_scaling"),
567        )
568        .right_from(state.ids.relative_to_win_button, 10.0)
569        .font_size(self.fonts.cyri.scale(14))
570        .font_id(self.fonts.cyri.conrod_id)
571        .graphics_for(state.ids.relative_to_win_button)
572        .color(TEXT_COLOR)
573        .set(state.ids.relative_to_win_text, ui);
574
575        // Absolute Scaling Button
576        let (check_img, check_mo_img, check_press_img, absolute_selected) = match ui_scale {
577            ScaleMode::Absolute(_) => (
578                self.imgs.check_checked,
579                self.imgs.check_checked_mo,
580                self.imgs.check_checked,
581                true,
582            ),
583            ScaleMode::RelativeToWindow(_) | ScaleMode::DpiFactor => (
584                self.imgs.check,
585                self.imgs.check_mo,
586                self.imgs.check_press,
587                false,
588            ),
589        };
590        if Button::image(check_img)
591            .w_h(12.0, 12.0)
592            .down_from(state.ids.relative_to_win_button, 8.0)
593            .hover_image(check_mo_img)
594            .press_image(check_press_img)
595            .set(state.ids.absolute_scale_button, ui)
596            .was_clicked()
597            && !absolute_selected
598        {
599            events.push(UiScale(ScaleChange::ToAbsolute));
600        }
601
602        Text::new(
603            &self
604                .localized_strings
605                .get_msg("hud-settings-custom_scaling"),
606        )
607        .right_from(state.ids.absolute_scale_button, 10.0)
608        .font_size(self.fonts.cyri.scale(14))
609        .font_id(self.fonts.cyri.conrod_id)
610        .graphics_for(state.ids.absolute_scale_button)
611        .color(TEXT_COLOR)
612        .set(state.ids.absolute_scale_text, ui);
613
614        // Slider -> Inactive when "Relative to window" is selected
615        if let ScaleMode::Absolute(scale) = ui_scale {
616            if let Some(new_val) = ImageSlider::continuous(
617                scale.log(2.0),
618                0.5f64.log(2.0),
619                2.0f64.log(2.0),
620                self.imgs.slider_indicator,
621                self.imgs.slider,
622            )
623            .w_h(208.0, 22.0)
624            .right_from(state.ids.absolute_scale_text, 12.0)
625            .track_breadth(30.0)
626            .slider_length(10.0)
627            .pad_track((5.0, 5.0))
628            .set(state.ids.ui_scale_slider, ui)
629            {
630                events.push(UiScale(ScaleChange::Adjust(2.0f64.powf(new_val))));
631            }
632            let mode_label_list = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0];
633            let selected = mode_label_list
634                .iter()
635                .position(|factor| (*factor - scale).abs() < 0.24);
636            // Dropdown menu for custom scaling
637            if let Some(clicked) = DropDownList::new(
638                &mode_label_list
639                    .iter()
640                    .map(|factor| format!("{n:.*}", 2, n = factor))
641                    .collect::<Vec<String>>(),
642                selected,
643            )
644            .w_h(208.0, 22.0)
645            .color(MENU_BG)
646            .label_color(TEXT_COLOR)
647            .label_font_size(self.fonts.cyri.scale(10))
648            .down_from(state.ids.ui_scale_slider, 6.0)
649            .set(state.ids.ui_scale_list, ui)
650            {
651                events.push(UiScale(ScaleChange::Adjust(mode_label_list[clicked])));
652            }
653            // Custom Scaling Text
654            Text::new(&format!("{:.2}", scale))
655                .right_from(state.ids.ui_scale_slider, 10.0)
656                .font_size(self.fonts.cyri.scale(14))
657                .font_id(self.fonts.cyri.conrod_id)
658                .color(TEXT_COLOR)
659                .set(state.ids.ui_scale_value, ui);
660        } else {
661            // Grey and unfunctional slider when Relative is selected
662            ImageSlider::continuous(0.0, 0.0, 1.0, self.imgs.nothing, self.imgs.slider)
663                .w_h(208.0, 22.0)
664                .right_from(state.ids.absolute_scale_text, 10.0)
665                .track_breadth(12.0)
666                .slider_length(10.0)
667                .track_color(Color::Rgba(1.0, 1.0, 1.0, 0.2))
668                .slider_color(Color::Rgba(1.0, 1.0, 1.0, 0.2))
669                .pad_track((5.0, 5.0))
670                .set(state.ids.ui_scale_slider, ui);
671        }
672
673        // Crosshair Options
674        // Crosshair Types
675        // Round
676        if Button::image(if let CrosshairType::Round = crosshair_type {
677            self.imgs.crosshair_bg_pressed
678        } else {
679            self.imgs.crosshair_bg
680        })
681        .w_h(15.0 * 4.0, 15.0 * 4.0)
682        .hover_image(if let CrosshairType::Round = crosshair_type {
683            self.imgs.crosshair_bg_pressed
684        } else {
685            self.imgs.crosshair_bg_hover
686        })
687        .press_image(if let CrosshairType::Round = crosshair_type {
688            self.imgs.crosshair_bg_pressed
689        } else {
690            self.imgs.crosshair_bg_press
691        })
692        .down_from(state.ids.ch_title, 20.0)
693        .set(state.ids.ch_1_bg, ui)
694        .was_clicked()
695        {
696            events.push(CrosshairType(CrosshairType::Round));
697        }
698
699        // Crosshair
700        Image::new(self.imgs.crosshair_outer_round)
701            .w_h(20.0 * 1.5, 20.0 * 1.5)
702            .middle_of(state.ids.ch_1_bg)
703            .color(Some(Color::Rgba(
704                1.0,
705                1.0,
706                1.0,
707                self.global_state.settings.interface.crosshair_opacity,
708            )))
709            .graphics_for(state.ids.ch_1_bg)
710            .set(state.ids.crosshair_outer_1, ui);
711        Image::new(self.imgs.crosshair_inner)
712            .w_h(21.0 * 2.0, 21.0 * 2.0)
713            .middle_of(state.ids.crosshair_outer_1)
714            .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6)))
715            .graphics_for(state.ids.ch_1_bg)
716            .set(state.ids.crosshair_inner_1, ui);
717
718        // Rounded Edges
719        if Button::image(if let CrosshairType::RoundEdges = crosshair_type {
720            self.imgs.crosshair_bg_pressed
721        } else {
722            self.imgs.crosshair_bg
723        })
724        .w_h(15.0 * 4.0, 15.0 * 4.0)
725        .hover_image(if let CrosshairType::RoundEdges = crosshair_type {
726            self.imgs.crosshair_bg_pressed
727        } else {
728            self.imgs.crosshair_bg_hover
729        })
730        .press_image(if let CrosshairType::RoundEdges = crosshair_type {
731            self.imgs.crosshair_bg_pressed
732        } else {
733            self.imgs.crosshair_bg_press
734        })
735        .right_from(state.ids.ch_1_bg, 20.0)
736        .set(state.ids.ch_2_bg, ui)
737        .was_clicked()
738        {
739            events.push(CrosshairType(CrosshairType::RoundEdges));
740        }
741
742        // Crosshair
743        Image::new(self.imgs.crosshair_outer_round_edges)
744            .w_h(21.0 * 1.5, 21.0 * 1.5)
745            .middle_of(state.ids.ch_2_bg)
746            .color(Some(Color::Rgba(
747                1.0,
748                1.0,
749                1.0,
750                self.global_state.settings.interface.crosshair_opacity,
751            )))
752            .graphics_for(state.ids.ch_2_bg)
753            .set(state.ids.crosshair_outer_2, ui);
754        Image::new(self.imgs.crosshair_inner)
755            .w_h(21.0 * 2.0, 21.0 * 2.0)
756            .middle_of(state.ids.crosshair_outer_2)
757            .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6)))
758            .graphics_for(state.ids.ch_2_bg)
759            .set(state.ids.crosshair_inner_2, ui);
760
761        // Edges
762        if Button::image(if let CrosshairType::Edges = crosshair_type {
763            self.imgs.crosshair_bg_pressed
764        } else {
765            self.imgs.crosshair_bg
766        })
767        .w_h(15.0 * 4.0, 15.0 * 4.0)
768        .hover_image(if let CrosshairType::Edges = crosshair_type {
769            self.imgs.crosshair_bg_pressed
770        } else {
771            self.imgs.crosshair_bg_hover
772        })
773        .press_image(if let CrosshairType::Edges = crosshair_type {
774            self.imgs.crosshair_bg_pressed
775        } else {
776            self.imgs.crosshair_bg_press
777        })
778        .right_from(state.ids.ch_2_bg, 20.0)
779        .set(state.ids.ch_3_bg, ui)
780        .was_clicked()
781        {
782            events.push(CrosshairType(CrosshairType::Edges));
783        }
784
785        // Crosshair
786        Image::new(self.imgs.crosshair_outer_edges)
787            .w_h(21.0 * 1.5, 21.0 * 1.5)
788            .middle_of(state.ids.ch_3_bg)
789            .color(Some(Color::Rgba(
790                1.0,
791                1.0,
792                1.0,
793                self.global_state.settings.interface.crosshair_opacity,
794            )))
795            .graphics_for(state.ids.ch_3_bg)
796            .set(state.ids.crosshair_outer_3, ui);
797        Image::new(self.imgs.crosshair_inner)
798            .w_h(21.0 * 2.0, 21.0 * 2.0)
799            .middle_of(state.ids.crosshair_outer_3)
800            .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.6)))
801            .graphics_for(state.ids.ch_3_bg)
802            .set(state.ids.crosshair_inner_3, ui);
803        // Crosshair Transparency Text and Slider
804        Text::new(&self.localized_strings.get_msg("hud-settings-crosshair"))
805            .down_from(state.ids.absolute_scale_button, 20.0)
806            .font_size(self.fonts.cyri.scale(18))
807            .font_id(self.fonts.cyri.conrod_id)
808            .color(TEXT_COLOR)
809            .set(state.ids.ch_title, ui);
810        Text::new(&self.localized_strings.get_msg("hud-settings-opacity"))
811            .right_from(state.ids.ch_3_bg, 20.0)
812            .font_size(self.fonts.cyri.scale(14))
813            .font_id(self.fonts.cyri.conrod_id)
814            .color(TEXT_COLOR)
815            .set(state.ids.ch_transp_text, ui);
816
817        if let Some(new_val) = ImageSlider::continuous(
818            crosshair_opacity,
819            0.0,
820            1.0,
821            self.imgs.slider_indicator,
822            self.imgs.slider,
823        )
824        .w_h(104.0, 22.0)
825        .down_from(state.ids.ch_transp_text, 8.0)
826        .track_breadth(12.0)
827        .slider_length(10.0)
828        .pad_track((5.0, 5.0))
829        .set(state.ids.ch_transp_slider, ui)
830        {
831            events.push(CrosshairTransp(new_val));
832        }
833
834        Text::new(&format!("{:.2}", crosshair_opacity,))
835            .right_from(state.ids.ch_transp_slider, 8.0)
836            .font_size(self.fonts.cyri.scale(14))
837            .graphics_for(state.ids.ch_transp_slider)
838            .font_id(self.fonts.cyri.conrod_id)
839            .color(TEXT_COLOR)
840            .set(state.ids.ch_transp_value, ui);
841
842        // Hotbar text
843        Text::new(&self.localized_strings.get_msg("hud-settings-hotbar"))
844            .down_from(state.ids.ch_1_bg, 20.0)
845            .font_size(self.fonts.cyri.scale(18))
846            .font_id(self.fonts.cyri.conrod_id)
847            .color(TEXT_COLOR)
848            .set(state.ids.hotbar_title, ui);
849        // Show Shortcut Numbers
850        if Button::image(
851            match self.global_state.settings.interface.shortcut_numbers {
852                ShortcutNumbers::On => self.imgs.checkbox_checked,
853                ShortcutNumbers::Off => self.imgs.checkbox,
854            },
855        )
856        .w_h(18.0, 18.0)
857        .hover_image(
858            match self.global_state.settings.interface.shortcut_numbers {
859                ShortcutNumbers::On => self.imgs.checkbox_checked_mo,
860                ShortcutNumbers::Off => self.imgs.checkbox_mo,
861            },
862        )
863        .press_image(
864            match self.global_state.settings.interface.shortcut_numbers {
865                ShortcutNumbers::On => self.imgs.checkbox_checked,
866                ShortcutNumbers::Off => self.imgs.checkbox_press,
867            },
868        )
869        .down_from(state.ids.hotbar_title, 8.0)
870        .set(state.ids.show_shortcuts_button, ui)
871        .was_clicked()
872        {
873            match self.global_state.settings.interface.shortcut_numbers {
874                ShortcutNumbers::On => events.push(ToggleShortcutNumbers(ShortcutNumbers::Off)),
875                ShortcutNumbers::Off => events.push(ToggleShortcutNumbers(ShortcutNumbers::On)),
876            }
877        }
878        Text::new(
879            &self
880                .localized_strings
881                .get_msg("hud-settings-toggle_shortcuts"),
882        )
883        .right_from(state.ids.show_shortcuts_button, 10.0)
884        .font_size(self.fonts.cyri.scale(14))
885        .font_id(self.fonts.cyri.conrod_id)
886        .color(TEXT_COLOR)
887        .set(state.ids.show_shortcuts_text, ui);
888        // Buff Position
889        // Buffs above skills
890        if Button::image(match self.global_state.settings.interface.buff_position {
891            BuffPosition::Bar => self.imgs.check_checked,
892            BuffPosition::Map => self.imgs.check,
893        })
894        .w_h(12.0, 12.0)
895        .hover_image(match self.global_state.settings.interface.buff_position {
896            BuffPosition::Bar => self.imgs.check_checked_mo,
897            BuffPosition::Map => self.imgs.check_mo,
898        })
899        .press_image(match self.global_state.settings.interface.buff_position {
900            BuffPosition::Bar => self.imgs.check_checked,
901            BuffPosition::Map => self.imgs.check_press,
902        })
903        .down_from(state.ids.show_shortcuts_button, 8.0)
904        .set(state.ids.buff_pos_bar_button, ui)
905        .was_clicked()
906        {
907            events.push(BuffPosition(BuffPosition::Bar))
908        }
909        Text::new(
910            &self
911                .localized_strings
912                .get_msg("hud-settings-buffs_skillbar"),
913        )
914        .right_from(state.ids.buff_pos_bar_button, 10.0)
915        .font_size(self.fonts.cyri.scale(14))
916        .font_id(self.fonts.cyri.conrod_id)
917        .graphics_for(state.ids.buff_pos_bar_button)
918        .color(TEXT_COLOR)
919        .set(state.ids.buff_pos_bar_text, ui);
920        // Buffs left from minimap
921        if Button::image(match self.global_state.settings.interface.buff_position {
922            BuffPosition::Map => self.imgs.check_checked,
923            BuffPosition::Bar => self.imgs.check,
924        })
925        .w_h(12.0, 12.0)
926        .hover_image(match self.global_state.settings.interface.buff_position {
927            BuffPosition::Map => self.imgs.check_checked_mo,
928            BuffPosition::Bar => self.imgs.check_mo,
929        })
930        .press_image(match self.global_state.settings.interface.buff_position {
931            BuffPosition::Map => self.imgs.check_checked,
932            BuffPosition::Bar => self.imgs.check_press,
933        })
934        .down_from(state.ids.buff_pos_bar_button, 8.0)
935        .set(state.ids.buff_pos_map_button, ui)
936        .was_clicked()
937        {
938            events.push(BuffPosition(BuffPosition::Map))
939        }
940        Text::new(&self.localized_strings.get_msg("hud-settings-buffs_mmap"))
941            .right_from(state.ids.buff_pos_map_button, 10.0)
942            .font_size(self.fonts.cyri.scale(14))
943            .font_id(self.fonts.cyri.conrod_id)
944            .graphics_for(state.ids.buff_pos_map_button)
945            .color(TEXT_COLOR)
946            .set(state.ids.buff_pos_map_text, ui);
947        // Slots text
948        Text::new(&self.localized_strings.get_msg("hud-settings-slots"))
949            .down_from(state.ids.buff_pos_map_button, 20.0)
950            .font_size(self.fonts.cyri.scale(18))
951            .font_id(self.fonts.cyri.conrod_id)
952            .color(TEXT_COLOR)
953            .set(state.ids.slots_title, ui);
954        // Prefix switch checkbox
955        let slots_use_prefixes = ToggleButton::new(
956            self.global_state.settings.interface.slots_use_prefixes,
957            self.imgs.checkbox,
958            self.imgs.checkbox_checked,
959        )
960        .w_h(18.0, 18.0)
961        .down_from(state.ids.slots_title, 20.0)
962        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
963        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
964        .set(state.ids.slots_use_prefixes_radio, ui);
965        if self.global_state.settings.interface.slots_use_prefixes != slots_use_prefixes {
966            events.push(SlotsUsePrefixes(
967                !self.global_state.settings.interface.slots_use_prefixes,
968            ));
969        }
970        Text::new(&self.localized_strings.get_msg("hud-settings-use_prefixes"))
971            .right_from(state.ids.slots_use_prefixes_radio, 10.0)
972            .font_size(self.fonts.cyri.scale(14))
973            .font_id(self.fonts.cyri.conrod_id)
974            .graphics_for(state.ids.slots_use_prefixes_radio)
975            .color(TEXT_COLOR)
976            .set(state.ids.slots_use_prefixes_text, ui);
977        if self.global_state.settings.interface.slots_use_prefixes {
978            let prefix_switch_point = self
979                .global_state
980                .settings
981                .interface
982                .slots_prefix_switch_point;
983
984            Text::new(
985                &self
986                    .localized_strings
987                    .get_msg("hud-settings-prefix_switch_point"),
988            )
989            .down_from(state.ids.slots_use_prefixes_radio, 8.0)
990            .right_from(state.ids.slots_use_prefixes_radio, 10.0)
991            .font_size(self.fonts.cyri.scale(14))
992            .font_id(self.fonts.cyri.conrod_id)
993            .color(TEXT_COLOR)
994            .set(state.ids.slots_prefix_switch_point_text, ui);
995            if let Some(new_val) = ImageSlider::discrete(
996                prefix_switch_point,
997                4,
998                7,
999                self.imgs.slider_indicator,
1000                self.imgs.slider,
1001            )
1002            .w_h(208.0, 22.0)
1003            .down_from(state.ids.slots_prefix_switch_point_text, 8.0)
1004            .track_breadth(30.0)
1005            .slider_length(10.0)
1006            .pad_track((5.0, 5.0))
1007            .set(state.ids.slots_prefix_switch_point_slider, ui)
1008            {
1009                events.push(SlotsPrefixSwitchPoint(new_val));
1010            }
1011            Text::new(&format!("{prefix_switch_point}"))
1012                .right_from(state.ids.slots_prefix_switch_point_slider, 10.0)
1013                .font_size(self.fonts.cyri.scale(14))
1014                .graphics_for(state.ids.slots_prefix_switch_point_slider)
1015                .font_id(self.fonts.cyri.conrod_id)
1016                .color(TEXT_COLOR)
1017                .set(state.ids.slots_prefix_switch_point_value, ui);
1018        }
1019
1020        // Content Right Side
1021
1022        /*Scrolling Combat text
1023
1024        O Show Damage Numbers
1025            Damage Accumulation Duration:
1026            [0s ----I----2s]
1027            O Show incoming Damage
1028                Incoming Damage Accumulation Duration:
1029                [0s ----I----2s]
1030            O Round Damage Numbers
1031            */
1032        // SCT/ Scrolling Combat Text
1033        Text::new(
1034            &self
1035                .localized_strings
1036                .get_msg("hud-settings-scrolling_combat_text"),
1037        )
1038        .top_left_with_margins_on(state.ids.window_r, 5.0, 5.0)
1039        .font_size(self.fonts.cyri.scale(18))
1040        .font_id(self.fonts.cyri.conrod_id)
1041        .color(TEXT_COLOR)
1042        .set(state.ids.sct_title, ui);
1043        // Generally toggle the SCT
1044        let show_sct = ToggleButton::new(
1045            self.global_state.settings.interface.sct,
1046            self.imgs.checkbox,
1047            self.imgs.checkbox_checked,
1048        )
1049        .w_h(18.0, 18.0)
1050        .down_from(state.ids.sct_title, 20.0)
1051        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1052        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1053        .set(state.ids.sct_show_radio, ui);
1054
1055        if self.global_state.settings.interface.sct != show_sct {
1056            events.push(Sct(!self.global_state.settings.interface.sct))
1057        }
1058        Text::new(
1059            &self
1060                .localized_strings
1061                .get_msg("hud-settings-scrolling_combat_text"),
1062        )
1063        .right_from(state.ids.sct_show_radio, 10.0)
1064        .font_size(self.fonts.cyri.scale(14))
1065        .font_id(self.fonts.cyri.conrod_id)
1066        .graphics_for(state.ids.sct_show_radio)
1067        .color(TEXT_COLOR)
1068        .set(state.ids.sct_show_text, ui);
1069        if self.global_state.settings.interface.sct {
1070            let sct_dmg_accum_duration =
1071                self.global_state.settings.interface.sct_dmg_accum_duration;
1072            let sct_inc_dmg_accum_duration = self
1073                .global_state
1074                .settings
1075                .interface
1076                .sct_inc_dmg_accum_duration;
1077
1078            Text::new(
1079                &self
1080                    .localized_strings
1081                    .get_msg("hud-settings-damage_accumulation_duration"),
1082            )
1083            .down_from(state.ids.sct_show_radio, 8.0)
1084            .right_from(state.ids.sct_show_radio, 10.0)
1085            .font_size(self.fonts.cyri.scale(14))
1086            .font_id(self.fonts.cyri.conrod_id)
1087            .color(TEXT_COLOR)
1088            .set(state.ids.sct_dmg_accum_duration_text, ui);
1089
1090            if let Some(new_val) = ImageSlider::continuous(
1091                sct_dmg_accum_duration,
1092                0.0,
1093                2.0,
1094                self.imgs.slider_indicator,
1095                self.imgs.slider,
1096            )
1097            .w_h(104.0, 22.0)
1098            .down_from(state.ids.sct_dmg_accum_duration_text, 8.0)
1099            .track_breadth(12.0)
1100            .slider_length(10.0)
1101            .pad_track((5.0, 5.0))
1102            .set(state.ids.sct_dmg_accum_duration_slider, ui)
1103            {
1104                events.push(SctDamageAccumDuration(new_val));
1105            }
1106
1107            Text::new(&format!("{:.2}", sct_dmg_accum_duration,))
1108                .right_from(state.ids.sct_dmg_accum_duration_slider, 8.0)
1109                .font_size(self.fonts.cyri.scale(14))
1110                .graphics_for(state.ids.sct_dmg_accum_duration_slider)
1111                .font_id(self.fonts.cyri.conrod_id)
1112                .color(TEXT_COLOR)
1113                .set(state.ids.sct_dmg_accum_duration_value, ui);
1114
1115            // Conditionally toggle incoming damage
1116            let show_inc_dmg = ToggleButton::new(
1117                self.global_state.settings.interface.sct_inc_dmg,
1118                self.imgs.checkbox,
1119                self.imgs.checkbox_checked,
1120            )
1121            .w_h(18.0, 18.0)
1122            .down_from(state.ids.sct_dmg_accum_duration_slider, 8.0)
1123            .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1124            .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1125            .set(state.ids.sct_show_inc_dmg_radio, ui);
1126
1127            if self.global_state.settings.interface.sct_inc_dmg != show_inc_dmg {
1128                events.push(SctIncomingDamage(
1129                    !self.global_state.settings.interface.sct_inc_dmg,
1130                ))
1131            }
1132            Text::new(
1133                &self
1134                    .localized_strings
1135                    .get_msg("hud-settings-incoming_damage"),
1136            )
1137            .right_from(state.ids.sct_show_inc_dmg_radio, 10.0)
1138            .font_size(self.fonts.cyri.scale(14))
1139            .font_id(self.fonts.cyri.conrod_id)
1140            .graphics_for(state.ids.sct_show_inc_dmg_radio)
1141            .color(TEXT_COLOR)
1142            .set(state.ids.sct_show_inc_dmg_text, ui);
1143            if self.global_state.settings.interface.sct_inc_dmg {
1144                Text::new(
1145                    &self
1146                        .localized_strings
1147                        .get_msg("hud-settings-incoming_damage_accumulation_duration"),
1148                )
1149                .down_from(state.ids.sct_show_inc_dmg_radio, 8.0)
1150                .right_from(state.ids.sct_show_inc_dmg_radio, 10.0)
1151                .font_size(self.fonts.cyri.scale(14))
1152                .font_id(self.fonts.cyri.conrod_id)
1153                .color(TEXT_COLOR)
1154                .set(state.ids.sct_inc_dmg_accum_duration_text, ui);
1155
1156                if let Some(new_val) = ImageSlider::continuous(
1157                    sct_inc_dmg_accum_duration,
1158                    0.0,
1159                    2.0,
1160                    self.imgs.slider_indicator,
1161                    self.imgs.slider,
1162                )
1163                .w_h(104.0, 22.0)
1164                .down_from(state.ids.sct_inc_dmg_accum_duration_text, 8.0)
1165                .track_breadth(12.0)
1166                .slider_length(10.0)
1167                .pad_track((5.0, 5.0))
1168                .set(state.ids.sct_inc_dmg_accum_duration_slider, ui)
1169                {
1170                    events.push(SctIncomingDamageAccumDuration(new_val));
1171                }
1172
1173                Text::new(&format!("{:.2}", sct_inc_dmg_accum_duration,))
1174                    .right_from(state.ids.sct_inc_dmg_accum_duration_slider, 8.0)
1175                    .font_size(self.fonts.cyri.scale(14))
1176                    .graphics_for(state.ids.sct_inc_dmg_accum_duration_slider)
1177                    .font_id(self.fonts.cyri.conrod_id)
1178                    .color(TEXT_COLOR)
1179                    .set(state.ids.sct_inc_dmg_accum_duration_value, ui);
1180            }
1181
1182            // Round Damage
1183            let show_sct_damage_rounding = ToggleButton::new(
1184                self.global_state.settings.interface.sct_damage_rounding,
1185                self.imgs.checkbox,
1186                self.imgs.checkbox_checked,
1187            )
1188            .w_h(18.0, 18.0)
1189            .down_from(
1190                if self.global_state.settings.interface.sct_inc_dmg {
1191                    state.ids.sct_inc_dmg_accum_duration_slider
1192                } else {
1193                    state.ids.sct_show_inc_dmg_radio
1194                },
1195                8.0,
1196            )
1197            .x_align_to(state.ids.sct_show_inc_dmg_radio, Align::Start)
1198            .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1199            .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1200            .set(state.ids.sct_round_dmg_radio, ui);
1201
1202            if self.global_state.settings.interface.sct_damage_rounding != show_sct_damage_rounding
1203            {
1204                events.push(SctRoundDamage(
1205                    !self.global_state.settings.interface.sct_damage_rounding,
1206                ))
1207            }
1208            Text::new(&self.localized_strings.get_msg("hud-settings-round_damage"))
1209                .right_from(state.ids.sct_round_dmg_radio, 10.0)
1210                .font_size(self.fonts.cyri.scale(14))
1211                .font_id(self.fonts.cyri.conrod_id)
1212                .graphics_for(state.ids.sct_round_dmg_radio)
1213                .color(TEXT_COLOR)
1214                .set(state.ids.sct_round_dmg_text, ui);
1215        }
1216
1217        // Speech bubbles
1218        Text::new(&self.localized_strings.get_msg("hud-settings-speech_bubble"))
1219            .down_from(
1220                if self.global_state.settings.interface.sct {
1221                    state.ids.sct_round_dmg_radio
1222                } else {
1223                    state.ids.sct_show_radio
1224                },
1225                20.0,
1226            )
1227            .x_align(Align::Start)
1228            .x_relative_to(state.ids.sct_show_text, -40.0)
1229            .font_size(self.fonts.cyri.scale(18))
1230            .font_id(self.fonts.cyri.conrod_id)
1231            .color(TEXT_COLOR)
1232            .set(state.ids.speech_bubble_text, ui);
1233
1234        // Show own speech bubbles
1235        let speech_bubble_self = ToggleButton::new(
1236            self.global_state.settings.interface.speech_bubble_self,
1237            self.imgs.checkbox,
1238            self.imgs.checkbox_checked,
1239        )
1240        .down_from(state.ids.speech_bubble_text, 10.0)
1241        .w_h(18.0, 18.0)
1242        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1243        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1244        .set(state.ids.speech_bubble_self_button, ui);
1245        if self.global_state.settings.interface.speech_bubble_self != speech_bubble_self {
1246            events.push(SpeechBubbleSelf(speech_bubble_self));
1247        }
1248        Text::new(
1249            &self
1250                .localized_strings
1251                .get_msg("hud-settings-speech_bubble_self"),
1252        )
1253        .right_from(state.ids.speech_bubble_self_button, 10.0)
1254        .font_size(self.fonts.cyri.scale(15))
1255        .font_id(self.fonts.cyri.conrod_id)
1256        .color(TEXT_COLOR)
1257        .set(state.ids.speech_bubble_self_text, ui);
1258
1259        // Speech bubble dark mode
1260        let speech_bubble_dark_mode = ToggleButton::new(
1261            self.global_state.settings.interface.speech_bubble_dark_mode,
1262            self.imgs.checkbox,
1263            self.imgs.checkbox_checked,
1264        )
1265        .down_from(state.ids.speech_bubble_self_button, 10.0)
1266        .w_h(18.0, 18.0)
1267        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1268        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1269        .set(state.ids.speech_bubble_dark_mode_button, ui);
1270        if self.global_state.settings.interface.speech_bubble_dark_mode != speech_bubble_dark_mode {
1271            events.push(SpeechBubbleDarkMode(speech_bubble_dark_mode));
1272        }
1273        Text::new(
1274            &self
1275                .localized_strings
1276                .get_msg("hud-settings-speech_bubble_dark_mode"),
1277        )
1278        .right_from(state.ids.speech_bubble_dark_mode_button, 10.0)
1279        .font_size(self.fonts.cyri.scale(15))
1280        .font_id(self.fonts.cyri.conrod_id)
1281        .color(TEXT_COLOR)
1282        .set(state.ids.speech_bubble_dark_mode_text, ui);
1283        // Speech bubble icon
1284        let speech_bubble_icon = ToggleButton::new(
1285            self.global_state.settings.interface.speech_bubble_icon,
1286            self.imgs.checkbox,
1287            self.imgs.checkbox_checked,
1288        )
1289        .down_from(state.ids.speech_bubble_dark_mode_button, 10.0)
1290        .w_h(18.0, 18.0)
1291        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1292        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1293        .set(state.ids.speech_bubble_icon_button, ui);
1294        if self.global_state.settings.interface.speech_bubble_icon != speech_bubble_icon {
1295            events.push(SpeechBubbleIcon(speech_bubble_icon));
1296        }
1297        Text::new(
1298            &self
1299                .localized_strings
1300                .get_msg("hud-settings-speech_bubble_icon"),
1301        )
1302        .right_from(state.ids.speech_bubble_icon_button, 10.0)
1303        .font_size(self.fonts.cyri.scale(15))
1304        .font_id(self.fonts.cyri.conrod_id)
1305        .color(TEXT_COLOR)
1306        .set(state.ids.speech_bubble_icon_text, ui);
1307
1308        // Energybars Numbers
1309        // Hotbar text
1310        Text::new(
1311            &self
1312                .localized_strings
1313                .get_msg("hud-settings-energybar_numbers"),
1314        )
1315        .down_from(state.ids.speech_bubble_icon_button, 20.0)
1316        .font_size(self.fonts.cyri.scale(18))
1317        .font_id(self.fonts.cyri.conrod_id)
1318        .color(TEXT_COLOR)
1319        .set(state.ids.bar_numbers_title, ui);
1320
1321        // None
1322        if Button::image(if let BarNumbers::Off = bar_values {
1323            self.imgs.check_checked
1324        } else {
1325            self.imgs.check
1326        })
1327        .w_h(12.0, 12.0)
1328        .hover_image(if let BarNumbers::Off = bar_values {
1329            self.imgs.check_checked_mo
1330        } else {
1331            self.imgs.check_mo
1332        })
1333        .press_image(if let BarNumbers::Off = bar_values {
1334            self.imgs.check_checked
1335        } else {
1336            self.imgs.check_press
1337        })
1338        .down_from(state.ids.bar_numbers_title, 8.0)
1339        .set(state.ids.show_bar_numbers_none_button, ui)
1340        .was_clicked()
1341        {
1342            events.push(ToggleBarNumbers(BarNumbers::Off))
1343        }
1344        Text::new(&self.localized_strings.get_msg("hud-settings-none"))
1345            .right_from(state.ids.show_bar_numbers_none_button, 10.0)
1346            .font_size(self.fonts.cyri.scale(14))
1347            .font_id(self.fonts.cyri.conrod_id)
1348            .graphics_for(state.ids.show_bar_numbers_none_button)
1349            .color(TEXT_COLOR)
1350            .set(state.ids.show_bar_numbers_none_text, ui);
1351
1352        // Values
1353        if Button::image(if let BarNumbers::Values = bar_values {
1354            self.imgs.check_checked
1355        } else {
1356            self.imgs.check
1357        })
1358        .w_h(12.0, 12.0)
1359        .hover_image(if let BarNumbers::Values = bar_values {
1360            self.imgs.check_checked_mo
1361        } else {
1362            self.imgs.check_mo
1363        })
1364        .press_image(if let BarNumbers::Values = bar_values {
1365            self.imgs.check_checked
1366        } else {
1367            self.imgs.check_press
1368        })
1369        .down_from(state.ids.show_bar_numbers_none_button, 8.0)
1370        .set(state.ids.show_bar_numbers_values_button, ui)
1371        .was_clicked()
1372        {
1373            events.push(ToggleBarNumbers(BarNumbers::Values))
1374        }
1375        Text::new(&self.localized_strings.get_msg("hud-settings-values"))
1376            .right_from(state.ids.show_bar_numbers_values_button, 10.0)
1377            .font_size(self.fonts.cyri.scale(14))
1378            .font_id(self.fonts.cyri.conrod_id)
1379            .graphics_for(state.ids.show_bar_numbers_values_button)
1380            .color(TEXT_COLOR)
1381            .set(state.ids.show_bar_numbers_values_text, ui);
1382
1383        // Percentages
1384        if Button::image(if let BarNumbers::Percent = bar_values {
1385            self.imgs.check_checked
1386        } else {
1387            self.imgs.check
1388        })
1389        .w_h(12.0, 12.0)
1390        .hover_image(if let BarNumbers::Percent = bar_values {
1391            self.imgs.check_checked_mo
1392        } else {
1393            self.imgs.check_mo
1394        })
1395        .press_image(if let BarNumbers::Percent = bar_values {
1396            self.imgs.check_checked
1397        } else {
1398            self.imgs.check_press
1399        })
1400        .down_from(state.ids.show_bar_numbers_values_button, 8.0)
1401        .set(state.ids.show_bar_numbers_percentage_button, ui)
1402        .was_clicked()
1403        {
1404            events.push(ToggleBarNumbers(BarNumbers::Percent))
1405        }
1406        Text::new(&self.localized_strings.get_msg("hud-settings-percentages"))
1407            .right_from(state.ids.show_bar_numbers_percentage_button, 10.0)
1408            .font_size(self.fonts.cyri.scale(14))
1409            .font_id(self.fonts.cyri.conrod_id)
1410            .graphics_for(state.ids.show_bar_numbers_percentage_button)
1411            .color(TEXT_COLOR)
1412            .set(state.ids.show_bar_numbers_percentage_text, ui);
1413
1414        // Always show energy bars
1415        let always_show_bars = ToggleButton::new(
1416            self.global_state.settings.interface.always_show_bars,
1417            self.imgs.checkbox,
1418            self.imgs.checkbox_checked,
1419        )
1420        .w_h(18.0, 18.0)
1421        .down_from(state.ids.show_bar_numbers_percentage_button, 20.0)
1422        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1423        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1424        .set(state.ids.always_show_bars_button, ui);
1425
1426        if always_show_bars != self.global_state.settings.interface.always_show_bars {
1427            events.push(ToggleAlwaysShowBars(always_show_bars));
1428        }
1429
1430        Text::new(
1431            &self
1432                .localized_strings
1433                .get_msg("hud-settings-always_show_bars"),
1434        )
1435        .right_from(state.ids.always_show_bars_button, 10.0)
1436        .font_size(self.fonts.cyri.scale(14))
1437        .font_id(self.fonts.cyri.conrod_id)
1438        .graphics_for(state.ids.always_show_bars_button)
1439        .color(TEXT_COLOR)
1440        .set(state.ids.always_show_bars_label, ui);
1441
1442        // Enable poise bar
1443        let enable_poise_bar = ToggleButton::new(
1444            self.global_state.settings.interface.enable_poise_bar,
1445            self.imgs.checkbox,
1446            self.imgs.checkbox_checked,
1447        )
1448        .w_h(18.0, 18.0)
1449        .down_from(state.ids.always_show_bars_button, 20.0)
1450        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1451        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1452        .set(state.ids.enable_poise_bar_button, ui);
1453
1454        if enable_poise_bar != self.global_state.settings.interface.enable_poise_bar {
1455            events.push(TogglePoiseBar(enable_poise_bar));
1456        }
1457
1458        Text::new(
1459            &self
1460                .localized_strings
1461                .get_msg("hud-settings-enable_poise_bar"),
1462        )
1463        .right_from(state.ids.enable_poise_bar_button, 10.0)
1464        .font_size(self.fonts.cyri.scale(14))
1465        .font_id(self.fonts.cyri.conrod_id)
1466        .graphics_for(state.ids.enable_poise_bar_button)
1467        .color(TEXT_COLOR)
1468        .set(state.ids.enable_poise_bar_label, ui);
1469
1470        // Toggle health SI prefixes
1471        let use_health_prefixes = ToggleButton::new(
1472            self.global_state.settings.interface.use_health_prefixes,
1473            self.imgs.checkbox,
1474            self.imgs.checkbox_checked,
1475        )
1476        .w_h(18.0, 18.0)
1477        .down_from(state.ids.enable_poise_bar_button, 20.0)
1478        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1479        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1480        .set(state.ids.use_health_prefixes_button, ui);
1481
1482        if use_health_prefixes != self.global_state.settings.interface.use_health_prefixes {
1483            events.push(ToggleHealthPrefixes(use_health_prefixes));
1484        }
1485
1486        Text::new(
1487            &self
1488                .localized_strings
1489                .get_msg("hud-settings-use_health_prefixes"),
1490        )
1491        .right_from(state.ids.use_health_prefixes_button, 10.0)
1492        .font_size(self.fonts.cyri.scale(14))
1493        .font_id(self.fonts.cyri.conrod_id)
1494        .graphics_for(state.ids.use_health_prefixes_button)
1495        .color(TEXT_COLOR)
1496        .set(state.ids.use_health_prefixes_text, ui);
1497
1498        // Experience Numbers
1499        Text::new(
1500            &self
1501                .localized_strings
1502                .get_msg("hud-settings-experience_numbers"),
1503        )
1504        .down_from(state.ids.use_health_prefixes_button, 20.0)
1505        .font_size(self.fonts.cyri.scale(18))
1506        .font_id(self.fonts.cyri.conrod_id)
1507        .color(TEXT_COLOR)
1508        .set(state.ids.experience_numbers_title, ui);
1509
1510        // Accumulate Experience Gained
1511        let accum_experience = ToggleButton::new(
1512            self.global_state.settings.interface.accum_experience,
1513            self.imgs.checkbox,
1514            self.imgs.checkbox_checked,
1515        )
1516        .w_h(18.0, 18.0)
1517        .down_from(state.ids.experience_numbers_title, 8.0)
1518        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1519        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1520        .set(state.ids.accum_experience_button, ui);
1521
1522        if self.global_state.settings.interface.accum_experience != accum_experience {
1523            events.push(AccumExperience(
1524                !self.global_state.settings.interface.accum_experience,
1525            ));
1526        }
1527
1528        Text::new(
1529            &self
1530                .localized_strings
1531                .get_msg("hud-settings-accumulate_experience"),
1532        )
1533        .right_from(state.ids.accum_experience_button, 10.0)
1534        .font_size(self.fonts.cyri.scale(14))
1535        .font_id(self.fonts.cyri.conrod_id)
1536        .graphics_for(state.ids.accum_experience_button)
1537        .color(TEXT_COLOR)
1538        .set(state.ids.accum_experience_text, ui);
1539
1540        // Minimap
1541        Text::new(&self.localized_strings.get_msg("hud-settings-minimap"))
1542            .down_from(state.ids.accum_experience_button, 20.0)
1543            .font_size(self.fonts.cyri.scale(18))
1544            .font_id(self.fonts.cyri.conrod_id)
1545            .color(TEXT_COLOR)
1546            .set(state.ids.minimap_title, ui);
1547
1548        // Scale
1549        let minimap_scale = self.global_state.settings.interface.minimap_scale;
1550        Text::new(&self.localized_strings.get_msg("hud-settings-minimap_scale"))
1551            .down_from(state.ids.minimap_title, 8.0)
1552            .font_size(self.fonts.cyri.scale(14))
1553            .font_id(self.fonts.cyri.conrod_id)
1554            .color(TEXT_COLOR)
1555            .set(state.ids.minimap_scale_text, ui);
1556
1557        if let Some(minimap_scale_new) = ImageSlider::continuous(
1558            minimap_scale,
1559            1.0,
1560            2.0,
1561            self.imgs.slider_indicator,
1562            self.imgs.slider,
1563        )
1564        .w_h(208.0, 22.0)
1565        .right_from(state.ids.minimap_scale_text, 10.0)
1566        .track_breadth(12.0)
1567        .slider_length(10.0)
1568        .pad_track((5.0, 5.0))
1569        .set(state.ids.minimap_scale_slider, ui)
1570        {
1571            events.push(MinimapScale(minimap_scale_new));
1572        }
1573
1574        Text::new(&format!("{:.2}", minimap_scale))
1575            .right_from(state.ids.minimap_scale_slider, 8.0)
1576            .font_size(self.fonts.cyri.scale(14))
1577            .graphics_for(state.ids.minimap_scale_slider)
1578            .font_id(self.fonts.cyri.conrod_id)
1579            .color(TEXT_COLOR)
1580            .set(state.ids.minimap_scale_value_text, ui);
1581
1582        // Colored Player Marker
1583        let minimap_colored_player_marker = ToggleButton::new(
1584            self.global_state
1585                .settings
1586                .interface
1587                .minimap_colored_player_marker,
1588            self.imgs.checkbox,
1589            self.imgs.checkbox_checked,
1590        )
1591        .down_from(state.ids.minimap_scale_text, 10.0)
1592        .w_h(18.0, 18.0)
1593        .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1594        .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1595        .set(state.ids.minimap_colored_player_marker_button, ui);
1596        if self
1597            .global_state
1598            .settings
1599            .interface
1600            .minimap_colored_player_marker
1601            != minimap_colored_player_marker
1602        {
1603            events.push(MinimapColoredPlayerMarker(
1604                !self
1605                    .global_state
1606                    .settings
1607                    .interface
1608                    .minimap_colored_player_marker,
1609            ));
1610        }
1611        Text::new(
1612            &self
1613                .localized_strings
1614                .get_msg("hud-settings-colored_player_marker"),
1615        )
1616        .right_from(state.ids.minimap_colored_player_marker_button, 10.0)
1617        .font_size(self.fonts.cyri.scale(14))
1618        .font_id(self.fonts.cyri.conrod_id)
1619        .color(TEXT_COLOR)
1620        .set(state.ids.minimap_colored_player_marker_text, ui);
1621
1622        // Reset the interface settings to the default settings
1623        if Button::image(self.imgs.button)
1624            .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
1625            .hover_image(self.imgs.button_hover)
1626            .press_image(self.imgs.button_press)
1627            .down_from(
1628                if self.global_state.settings.interface.slots_use_prefixes {
1629                    state.ids.slots_prefix_switch_point_slider
1630                } else {
1631                    state.ids.slots_use_prefixes_radio
1632                },
1633                12.0,
1634            )
1635            .x_align_to(state.ids.slots_use_prefixes_radio, Align::Start)
1636            .label(
1637                &self
1638                    .localized_strings
1639                    .get_msg("hud-settings-reset_interface"),
1640            )
1641            .label_font_size(self.fonts.cyri.scale(14))
1642            .label_color(TEXT_COLOR)
1643            .label_font_id(self.fonts.cyri.conrod_id)
1644            .label_y(Relative::Scalar(2.0))
1645            .set(state.ids.reset_interface_button, ui)
1646            .was_clicked()
1647        {
1648            events.push(ResetInterfaceSettings);
1649        }
1650
1651        events
1652    }
1653}