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