diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index ecd6f5224a..160bbc7914 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -100,7 +100,7 @@ fn main() { // Set up the initial play state let mut states: Vec> = vec![Box::new(MainMenuState::new( - &mut global_state.window, + &mut global_state, ))]; states.last().map(|current_state| { log::info!("Started game with state '{}'", current_state.name()) diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index 9baba60a47..ed62409f1e 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -21,9 +21,9 @@ pub struct MainMenuState { impl MainMenuState { /// Create a new `MainMenuState` - pub fn new(window: &mut Window) -> Self { + pub fn new(global_state: &mut GlobalState) -> Self { Self { - main_menu_ui: MainMenuUi::new(window), + main_menu_ui: MainMenuUi::new(global_state), } } } @@ -85,13 +85,19 @@ impl PlayState for MainMenuState { // Maintain the UI for event in self .main_menu_ui - .maintain(global_state.window.renderer_mut()) + .maintain(global_state) { match event { MainMenuEvent::LoginAttempt { username, server_address, } => { + let mut net_settings = &mut global_state.settings.networking; + net_settings.username = username.clone(); + if !net_settings.servers.contains(&server_address) { + net_settings.servers.push(server_address.clone()); + } + global_state.settings.save_to_file(); const DEFAULT_PORT: u16 = 59003; // Don't try to connect if there is already a connection in progress client_init = client_init.or(Some(ClientInit::new( diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index d14e75686e..c082ec8966 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -2,19 +2,16 @@ use crate::{ render::Renderer, ui::{self, ScaleMode, Ui}, window::Window, - DEFAULT_PUBLIC_SERVER, -}; -use common::{ - assets, - figure::Segment, + GlobalState, DEFAULT_PUBLIC_SERVER, }; +use common::{assets, figure::Segment}; use conrod_core::{ color, color::TRANSPARENT, image::Id as ImgId, position::{Dimension, Relative}, text::font::Id as FontId, - widget::{text_box::Event as TextBoxEvent, Button, Image, Rectangle, Text, TextBox}, + widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; @@ -37,8 +34,12 @@ widget_ids! { username_field, singleplayer_button, singleplayer_text, - // Buttons + // Serverlist servers_button, + servers_frame, + servers_text, + servers_close, + // Buttons settings_button, quit_button, // Error @@ -134,10 +135,13 @@ pub struct MainMenuUi { server_address: String, login_error: Option, connecting: Option, + show_servers: bool, } impl MainMenuUi { - pub fn new(window: &mut Window) -> Self { + pub fn new(global_state: &mut GlobalState) -> Self { + let mut window = &mut global_state.window; + let networking = &global_state.settings.networking; let mut ui = Ui::new(window).unwrap(); // TODO: adjust/remove this, right now it is used to demonstrate window scaling functionality ui.scaling_mode(ScaleMode::RelativeToWindow([1920.0, 1080.0].into())); @@ -148,10 +152,12 @@ impl MainMenuUi { // Load fonts let load_font = |filename, ui: &mut Ui| { let fullpath: String = ["/voxygen/font", filename].concat(); - ui.new_font(conrod_core::text::Font::from_bytes( - assets::load(fullpath.as_str()) - .expect("Error loading file") - ).unwrap()) + ui.new_font( + conrod_core::text::Font::from_bytes( + assets::load(fullpath.as_str()).expect("Error loading file"), + ) + .unwrap(), + ) }; let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui); let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui); @@ -162,14 +168,15 @@ impl MainMenuUi { ids, font_metamorph, font_opensans, - username: "Username".to_string(), - server_address: DEFAULT_PUBLIC_SERVER.to_string(), + username: networking.username.clone(), + server_address: networking.servers[networking.default_server].clone(), login_error: None, connecting: None, + show_servers: false, } } - fn update_layout(&mut self) -> Vec { + fn update_layout(&mut self, global_state: &GlobalState) -> Vec { let mut events = Vec::new(); let ref mut ui_widgets = self.ui.set_widgets(); let version = env!("CARGO_PKG_VERSION"); @@ -273,6 +280,66 @@ impl MainMenuUi { self.login_error = None }; } + if self.show_servers { + Image::new(self.imgs.error_frame) + .top_left_with_margins_on(ui_widgets.window, 3.0, 3.0) + .w_h(400.0, 400.0) + .set(self.ids.servers_frame, ui_widgets); + + let netsettings = &global_state.settings.networking; + + let (mut items, scrollbar) = List::flow_down(netsettings.servers.len()) + .top_left_with_margins_on(self.ids.servers_frame, 0.0, 5.0) + .w_h(400.0, 300.0) + .scrollbar_next_to() + .scrollbar_thickness(18.0) + .scrollbar_color(TEXT_COLOR) + .set(self.ids.servers_text, ui_widgets); + + while let Some(item) = items.next(ui_widgets) { + let mut text = "".to_string(); + if &netsettings.servers[item.i] == &self.server_address { + text.push_str("* ") + } else { + text.push_str(" ") + } + text.push_str(&netsettings.servers[item.i]); + + if item + .set( + Button::image(self.imgs.button_dark) + .w_h(100.0, 53.0) + .mid_bottom_with_margin_on(self.ids.servers_frame, 5.0) + .hover_image(self.imgs.button_dark_hover) + .press_image(self.imgs.button_dark_press) + .label_y(Relative::Scalar(2.0)) + .label(&text) + .label_font_size(20) + .label_color(TEXT_COLOR), + ui_widgets, + ) + .was_clicked() + { + // TODO: Set as current server address + self.server_address = netsettings.servers[item.i].clone(); + } + } + + if Button::image(self.imgs.button_dark) + .w_h(200.0, 53.0) + .mid_bottom_with_margin_on(self.ids.servers_frame, 5.0) + .hover_image(self.imgs.button_dark_hover) + .press_image(self.imgs.button_dark_press) + .label_y(Relative::Scalar(2.0)) + .label("Close") + .label_font_size(20) + .label_color(TEXT_COLOR) + .set(self.ids.servers_close, ui_widgets) + .was_clicked() + { + self.show_servers = false + }; + } // Server address Image::new(self.imgs.input_bg) .w_h(337.0, 67.0) @@ -352,7 +419,6 @@ impl MainMenuUi { .was_clicked() { singleplayer!(); - login!(); } // Quit if Button::image(self.imgs.button) @@ -394,7 +460,9 @@ impl MainMenuUi { .label_y(Relative::Scalar(3.0)) .set(self.ids.servers_button, ui_widgets) .was_clicked() - {}; + { + self.show_servers = true; + }; events } @@ -412,9 +480,9 @@ impl MainMenuUi { self.ui.handle_event(event); } - pub fn maintain(&mut self, renderer: &mut Renderer) -> Vec { - let events = self.update_layout(); - self.ui.maintain(renderer); + pub fn maintain(&mut self, global_state: &mut GlobalState) -> Vec { + let events = self.update_layout(global_state); + self.ui.maintain(global_state.window.renderer_mut()); events } diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 86d90cb446..9b4205972b 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -14,6 +14,7 @@ use std::default::Default; #[serde(default)] pub struct Settings { pub controls: ControlSettings, + pub networking: NetworkingSettings, } /// ControlSettings contains keybindings @@ -37,6 +38,13 @@ pub struct ControlSettings { pub toggle_interface: VirtualKeyCode, } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct NetworkingSettings { + pub username: String, + pub servers: Vec, + pub default_server: usize, +} + impl Default for Settings { fn default() -> Self { Settings { @@ -58,6 +66,11 @@ impl Default for Settings { help: VirtualKeyCode::F1, toggle_interface: VirtualKeyCode::F2, }, + networking: NetworkingSettings { + username: "Username".to_string(), + servers: vec!("server.veloren.net".to_string()), + default_server: 0, + }, } }