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