Skip to main content

veloren_voxygen/hud/settings_window/
interface.rs

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