veloren_voxygen/hud/settings_window/
mod.rs

1mod accessibility;
2mod chat;
3mod controls;
4mod gameplay;
5mod interface;
6mod language;
7mod networking;
8mod sound;
9mod video;
10
11use crate::{
12    GlobalState,
13    hud::{Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, img_ids::Imgs},
14    session::settings_change::SettingsChange,
15    ui::fonts::Fonts,
16};
17use conrod_core::{
18    Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, color,
19    widget::{self, Button, Image, Rectangle, Text},
20    widget_ids,
21};
22use i18n::Localization;
23
24use strum::{EnumIter, IntoEnumIterator};
25
26widget_ids! {
27    struct Ids {
28        frame,
29        settings_bg,
30        tabs_align,
31        icon,
32        settings_close,
33        settings_title,
34        settings_content_align,
35
36        tabs[],
37        interface,
38        gameplay,
39        controls,
40        video,
41        sound,
42        language,
43        chat,
44        networking,
45        accessibility,
46    }
47}
48
49const RESET_BUTTONS_HEIGHT: f64 = 34.0;
50const RESET_BUTTONS_WIDTH: f64 = 155.0;
51
52#[derive(Debug, EnumIter, PartialEq, Eq)]
53pub enum SettingsTab {
54    Interface,
55    Chat,
56    Video,
57    Sound,
58    Gameplay,
59    Controls,
60    Lang,
61    Networking,
62    Accessibility,
63}
64impl SettingsTab {
65    fn name_key(&self) -> &str {
66        match self {
67            SettingsTab::Interface => "common-interface",
68            SettingsTab::Chat => "common-chat",
69            SettingsTab::Gameplay => "common-gameplay",
70            SettingsTab::Controls => "common-controls",
71            SettingsTab::Video => "common-video",
72            SettingsTab::Sound => "common-sound",
73            SettingsTab::Lang => "common-languages",
74            SettingsTab::Networking => "common-networking",
75            SettingsTab::Accessibility => "common-accessibility",
76        }
77    }
78
79    fn title_key(&self) -> &str {
80        match self {
81            SettingsTab::Interface => "common-interface_settings",
82            SettingsTab::Chat => "common-chat_settings",
83            SettingsTab::Gameplay => "common-gameplay_settings",
84            SettingsTab::Controls => "common-controls_settings",
85            SettingsTab::Video => "common-video_settings",
86            SettingsTab::Sound => "common-sound_settings",
87            SettingsTab::Lang => "common-language_settings",
88            SettingsTab::Networking => "common-networking_settings",
89            SettingsTab::Accessibility => "common-accessibility_settings",
90        }
91    }
92}
93
94#[derive(WidgetCommon)]
95pub struct SettingsWindow<'a> {
96    global_state: &'a GlobalState,
97    show: &'a Show,
98    imgs: &'a Imgs,
99    fonts: &'a Fonts,
100    localized_strings: &'a Localization,
101    server_view_distance_limit: Option<u32>,
102    fps: f32,
103    #[conrod(common_builder)]
104    common: widget::CommonBuilder,
105}
106
107impl<'a> SettingsWindow<'a> {
108    pub fn new(
109        global_state: &'a GlobalState,
110        show: &'a Show,
111        imgs: &'a Imgs,
112        fonts: &'a Fonts,
113        localized_strings: &'a Localization,
114        server_view_distance_limit: Option<u32>,
115        fps: f32,
116    ) -> Self {
117        Self {
118            global_state,
119            show,
120            imgs,
121            fonts,
122            localized_strings,
123            server_view_distance_limit,
124            fps,
125            common: widget::CommonBuilder::default(),
126        }
127    }
128}
129
130pub struct State {
131    ids: Ids,
132}
133
134pub enum Event {
135    ChangeTab(SettingsTab),
136    Close,
137    SettingsChange(SettingsChange),
138    ChangeChatSettingsTab(Option<usize>),
139    ResetBindingMode,
140}
141
142#[derive(Clone)]
143pub enum ScaleChange {
144    ToAbsolute,
145    ToRelative,
146    Adjust(f64),
147}
148
149impl Widget for SettingsWindow<'_> {
150    type Event = Vec<Event>;
151    type State = State;
152    type Style = ();
153
154    fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
155        State {
156            ids: Ids::new(id_gen),
157        }
158    }
159
160    fn style(&self) -> Self::Style {}
161
162    fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
163        common_base::prof_span!("SettingsWindow::update");
164        let widget::UpdateArgs { state, ui, .. } = args;
165
166        let mut events = Vec::new();
167        let tab_font_scale = 18;
168
169        // Frame
170        Image::new(self.imgs.settings_bg)
171            .w_h(1052.0, 886.0)
172            .mid_top_with_margin_on(ui.window, 5.0)
173            .color(Some(UI_MAIN))
174            .set(state.ids.settings_bg, ui);
175
176        Image::new(self.imgs.settings_frame)
177            .w_h(1052.0, 886.0)
178            .middle_of(state.ids.settings_bg)
179            .color(Some(UI_HIGHLIGHT_0))
180            .set(state.ids.frame, ui);
181
182        // Content Alignment
183        Rectangle::fill_with([814.0, 834.0], color::TRANSPARENT)
184            .top_right_with_margins_on(state.ids.frame, 46.0, 2.0)
185            .set(state.ids.settings_content_align, ui);
186
187        // Tabs Content Alignment
188        Rectangle::fill_with([232.0, 814.0], color::TRANSPARENT)
189            .top_left_with_margins_on(state.ids.frame, 44.0, 2.0)
190            .scroll_kids()
191            .scroll_kids_vertically()
192            .set(state.ids.tabs_align, ui);
193
194        // Icon
195        Image::new(self.imgs.settings)
196            .w_h(29.0 * 1.5, 25.0 * 1.5)
197            .top_left_with_margins_on(state.ids.frame, 2.0, 1.0)
198            .set(state.ids.icon, ui);
199        // Title
200        Text::new(
201            &self
202                .localized_strings
203                .get_msg(self.show.settings_tab.title_key()),
204        )
205        .mid_top_with_margin_on(state.ids.frame, 3.0)
206        .font_id(self.fonts.cyri.conrod_id)
207        .font_size(self.fonts.cyri.scale(29))
208        .color(TEXT_COLOR)
209        .set(state.ids.settings_title, ui);
210
211        // X-Button
212        if Button::image(self.imgs.close_button)
213            .w_h(24.0, 25.0)
214            .hover_image(self.imgs.close_btn_hover)
215            .press_image(self.imgs.close_btn_press)
216            .top_right_with_margins_on(state.ids.frame, 0.0, 0.0)
217            .set(state.ids.settings_close, ui)
218            .was_clicked()
219        {
220            events.push(Event::Close);
221            events.push(Event::ResetBindingMode); // stop input mapping if window closed
222        }
223
224        // Tabs
225        if state.ids.tabs.len() < SettingsTab::iter().len() {
226            state.update(|s| {
227                s.ids
228                    .tabs
229                    .resize(SettingsTab::iter().len(), &mut ui.widget_id_generator())
230            });
231        }
232        for (i, settings_tab) in SettingsTab::iter().enumerate() {
233            let tab_name = self.localized_strings.get_msg(settings_tab.name_key());
234            let mut button = Button::image(if self.show.settings_tab == settings_tab {
235                self.imgs.selection
236            } else {
237                self.imgs.nothing
238            })
239            .w_h(230.0, 48.0)
240            .hover_image(self.imgs.selection_hover)
241            .press_image(self.imgs.selection_press)
242            .image_color(color::rgba(1.0, 0.82, 0.27, 1.0))
243            .label(&tab_name)
244            .label_font_size(self.fonts.cyri.scale(tab_font_scale))
245            .label_font_id(self.fonts.cyri.conrod_id)
246            .label_color(TEXT_COLOR);
247
248            button = if i == 0 {
249                button.mid_top_with_margin_on(state.ids.tabs_align, 28.0)
250            } else {
251                button.down_from(state.ids.tabs[i - 1], 0.0)
252            };
253
254            if button.set(state.ids.tabs[i], ui).was_clicked() {
255                events.push(Event::ChangeTab(settings_tab));
256                events.push(Event::ResetBindingMode); // stop input mapping if tab changed
257            }
258        }
259
260        // Content Area
261        let global_state = self.global_state;
262        let imgs = self.imgs;
263        let fonts = self.fonts;
264        let localized_strings = self.localized_strings;
265        match self.show.settings_tab {
266            SettingsTab::Interface => {
267                for change in
268                    interface::Interface::new(global_state, imgs, fonts, localized_strings)
269                        .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
270                        .wh_of(state.ids.settings_content_align)
271                        .set(state.ids.interface, ui)
272                {
273                    events.push(Event::SettingsChange(change.into()));
274                }
275            },
276            SettingsTab::Chat => {
277                for event in
278                    chat::Chat::new(global_state, self.show, imgs, fonts, localized_strings)
279                        .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
280                        .wh_of(state.ids.settings_content_align)
281                        .set(state.ids.chat, ui)
282                {
283                    match event {
284                        chat::Event::ChatChange(change) => {
285                            events.push(Event::SettingsChange(change.into()));
286                        },
287                        chat::Event::ChangeChatSettingsTab(index) => {
288                            events.push(Event::ChangeChatSettingsTab(index));
289                        },
290                    }
291                }
292            },
293            SettingsTab::Gameplay => {
294                for change in gameplay::Gameplay::new(global_state, imgs, fonts, localized_strings)
295                    .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
296                    .wh_of(state.ids.settings_content_align)
297                    .set(state.ids.gameplay, ui)
298                {
299                    events.push(Event::SettingsChange(change.into()));
300                }
301            },
302            SettingsTab::Controls => {
303                for change in controls::Controls::new(global_state, imgs, fonts, localized_strings)
304                    .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
305                    .wh_of(state.ids.settings_content_align)
306                    .set(state.ids.controls, ui)
307                {
308                    events.push(Event::SettingsChange(change.into()));
309                }
310            },
311            SettingsTab::Video => {
312                for change in video::Video::new(
313                    global_state,
314                    imgs,
315                    fonts,
316                    localized_strings,
317                    self.server_view_distance_limit,
318                    self.fps,
319                )
320                .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
321                .wh_of(state.ids.settings_content_align)
322                .set(state.ids.video, ui)
323                {
324                    events.push(Event::SettingsChange(change.into()));
325                }
326            },
327            SettingsTab::Sound => {
328                for change in sound::Sound::new(global_state, imgs, fonts, localized_strings)
329                    .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
330                    .wh_of(state.ids.settings_content_align)
331                    .set(state.ids.sound, ui)
332                {
333                    events.push(Event::SettingsChange(change.into()));
334                }
335            },
336            SettingsTab::Lang => {
337                for change in language::Language::new(global_state, imgs, fonts, localized_strings)
338                    .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
339                    .wh_of(state.ids.settings_content_align)
340                    .set(state.ids.language, ui)
341                {
342                    events.push(Event::SettingsChange(change.into()));
343                }
344            },
345            SettingsTab::Networking => {
346                for change in networking::Networking::new(
347                    global_state,
348                    imgs,
349                    fonts,
350                    localized_strings,
351                    self.server_view_distance_limit,
352                )
353                .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
354                .wh_of(state.ids.settings_content_align)
355                .set(state.ids.networking, ui)
356                {
357                    events.push(Event::SettingsChange(change.into()));
358                }
359            },
360            SettingsTab::Accessibility => {
361                for change in
362                    accessibility::Accessibility::new(global_state, imgs, fonts, localized_strings)
363                        .top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
364                        .wh_of(state.ids.settings_content_align)
365                        .set(state.ids.accessibility, ui)
366                {
367                    events.push(Event::SettingsChange(change.into()));
368                }
369            },
370        }
371
372        events
373    }
374}