diff --git a/assets/voxygen/background/bg_load.png b/assets/voxygen/background/bg_load.png new file mode 100644 index 0000000000..dd7475b803 --- /dev/null +++ b/assets/voxygen/background/bg_load.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f921e77caaec26473711e39ecf421248b87d9d597fbdeab28a2433c5d9ff0fd +size 1064297 diff --git a/assets/voxygen/voxel/figure/accessory/elf/warpaint-0.vox b/assets/voxygen/voxel/figure/accessory/elf/warpaint-0.vox index 89000b9620..8ead89038e 100644 --- a/assets/voxygen/voxel/figure/accessory/elf/warpaint-0.vox +++ b/assets/voxygen/voxel/figure/accessory/elf/warpaint-0.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43a631215ad8ded5108a2563c9cebe544d6132e13b171169aa1a1f5e4fbf0daa -size 44220 +oid sha256:722b4f8936664fcd2c612bd827583c46f91d4581bb51c310fd5b04fff34c421b +size 55604 diff --git a/assets/voxygen/voxel/figure/hair/dwarf/female-0.vox b/assets/voxygen/voxel/figure/hair/dwarf/female-0.vox index effabde072..6189315569 100644 --- a/assets/voxygen/voxel/figure/hair/dwarf/female-0.vox +++ b/assets/voxygen/voxel/figure/hair/dwarf/female-0.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:18e5ee627f15bb36b9a01c66b381aad09f782290d471a815a58b8afa8301ab28 +oid sha256:e97833f7e1e5420dd3193b15738eaae01cc42ee5ea0a10c25f70d0d631cfe234 size 59195 diff --git a/assets/voxygen/voxel/figure/hair/dwarf/female-1.vox b/assets/voxygen/voxel/figure/hair/dwarf/female-1.vox new file mode 100644 index 0000000000..d042496f30 --- /dev/null +++ b/assets/voxygen/voxel/figure/hair/dwarf/female-1.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a23aa08a25fcd292a16eb896f9b8826fe6caefbc4642a2cde3aa89db581d2d04 +size 59323 diff --git a/assets/voxygen/voxel/figure/hair/elf/male-3.vox b/assets/voxygen/voxel/figure/hair/elf/male-3.vox new file mode 100644 index 0000000000..c2f735d7a0 --- /dev/null +++ b/assets/voxygen/voxel/figure/hair/elf/male-3.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:003df0ac0d6115d676fe153431b111fd69a327893004785040bf92fb32c11492 +size 59276 diff --git a/assets/voxygen/voxel/humanoid_head_manifest.ron b/assets/voxygen/voxel/humanoid_head_manifest.ron index 2b1bc8a3f0..4d9139d5d8 100644 --- a/assets/voxygen/voxel/humanoid_head_manifest.ron +++ b/assets/voxygen/voxel/humanoid_head_manifest.ron @@ -113,6 +113,7 @@ Some(("figure.hair.elf.male-0", (2, 1, 1))), Some(("figure.hair.elf.male-1", (1, -1, 0))), Some(("figure.hair.elf.male-2", (-2, -4, -7))), + Some(("figure.hair.elf.male-3", (-7, -10, -8))), ], beard: [None], accessory: [ @@ -150,7 +151,7 @@ beard: [None], accessory: [ None, - Some(("figure.accessory.elf.warpaint-0", (6, 9, 4))), ] + Some(("figure.accessory.elf.warpaint-0", (6, 9, 5))),] ), (Dwarf, Male): ( offset: (-6.0, -4.5, -6.0), @@ -193,7 +194,8 @@ head: ("figure.head.dwarf.female", (0, 3, 0)), eyes: ("figure.eyes.dwarf.female-0", (1, 10, 2)), hair: [ - Some(("figure.hair.dwarf.female-0", (0, 0, -7))), + Some(("figure.hair.dwarf.female-0", (-9, -9, -7))), + Some(("figure.hair.dwarf.female-1", (-9, -9, -7))), ], beard: [None], accessory: [ diff --git a/common/src/comp/body/humanoid.rs b/common/src/comp/body/humanoid.rs index bb6ed9a06a..53be221bf8 100644 --- a/common/src/comp/body/humanoid.rs +++ b/common/src/comp/body/humanoid.rs @@ -332,10 +332,10 @@ impl Race { match (self, body_type) { (Race::Danari, BodyType::Female) => 2, (Race::Danari, BodyType::Male) => 2, - (Race::Dwarf, BodyType::Female) => 1, + (Race::Dwarf, BodyType::Female) => 2, (Race::Dwarf, BodyType::Male) => 3, (Race::Elf, BodyType::Female) => 21, - (Race::Elf, BodyType::Male) => 3, + (Race::Elf, BodyType::Male) => 4, (Race::Human, BodyType::Female) => 19, (Race::Human, BodyType::Male) => 17, (Race::Orc, BodyType::Female) => 1, diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index a824be15bb..621c759ac0 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -98,7 +98,10 @@ impl PlayState for MainMenuState { global_state.maintain(clock.get_last_delta().as_secs_f32()); // Maintain the UI. - for event in self.main_menu_ui.maintain(global_state) { + for event in self + .main_menu_ui + .maintain(global_state, clock.get_last_delta()) + { match event { MainMenuEvent::LoginAttempt { username, diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index cbb24f6fa6..5c62db41c1 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -14,6 +14,7 @@ use conrod_core::{ widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; +use std::time::Duration; widget_ids! { struct Ids { @@ -83,6 +84,7 @@ image_ids! { bg: "voxygen.background.bg_main", + load: "voxygen.background.bg_load", nothing: (), @@ -127,7 +129,6 @@ pub enum PopupType { Error, ConnectionInfo, } - pub struct PopupData { msg: String, button_text: String, @@ -145,8 +146,10 @@ pub struct MainMenuUi { server_address: String, popup: Option, connecting: Option, + connect: bool, show_servers: bool, show_disclaimer: bool, + time: f32, } impl MainMenuUi { @@ -177,12 +180,16 @@ impl MainMenuUi { popup: None, connecting: None, show_servers: false, + connect: false, + time: 0.0, show_disclaimer: global_state.settings.show_disclaimer, } } - fn update_layout(&mut self, global_state: &mut GlobalState) -> Vec { + fn update_layout(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec { let mut events = Vec::new(); + self.time = self.time + dt.as_secs_f32(); + let fade_msg = (self.time * 2.0).sin() * 0.5 + 0.51; let (ref mut ui_widgets, ref mut _tooltip_manager) = self.ui.set_widgets(); let version = format!( "{}-{}", @@ -196,9 +203,6 @@ impl MainMenuUi { \n\ The name you put in will be your character name ingame.\n\ \n\ - Starting Singleplayer needs some time to load.\n\ - During this time the game may appear unresponsive.\n\ - \n\ As of now you can't save your characters.\n\ Changing their appearance is possible though."; @@ -222,429 +226,459 @@ impl MainMenuUi { // Background image, Veloren logo, Alpha-Version Label - Image::new(self.imgs.bg) - .middle_of(ui_widgets.window) - .set(self.ids.bg, ui_widgets); - - Image::new(self.imgs.banner) - .w_h(65.0 * 6.0, 100.0 * 6.0) - .middle_of(self.ids.bg) - .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.9))) - .set(self.ids.banner, ui_widgets); - - Image::new(self.imgs.banner_top) - .w_h(65.0 * 6.0, 1.0 * 6.0) - .mid_top_with_margin_on(self.ids.banner, 0.0) - .set(self.ids.banner_top, ui_widgets); - - // Logo - Image::new(self.imgs.v_logo) - .w_h(123.0 * 2.5, 35.0 * 2.5) - .mid_top_with_margin_on(self.ids.banner_top, 40.0) - .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.95))) - .set(self.ids.v_logo, ui_widgets); + Image::new(if self.connect { + self.imgs.load + } else { + self.imgs.bg + }) + .middle_of(ui_widgets.window) + .set(self.ids.bg, ui_widgets); // Version displayed top right corner Text::new(&version) + .color(TEXT_COLOR) .top_right_with_margins_on(ui_widgets.window, 5.0, 5.0) + .font_id(self.fonts.cyri) .font_size(14) - .font_id(self.fonts.cyri) - .color(TEXT_COLOR) .set(self.ids.version, ui_widgets); - - if self.show_disclaimer { - Image::new(self.imgs.disclaimer) - .w_h(1800.0, 800.0) - .middle_of(ui_widgets.window) - .scroll_kids() - .scroll_kids_vertically() - .set(self.ids.disc_window, ui_widgets); - - Text::new("Disclaimer") - .top_left_with_margins_on(self.ids.disc_window, 30.0, 40.0) - .font_size(35) - .font_id(self.fonts.alkhemi) - .color(TEXT_COLOR) - .set(self.ids.disc_text_1, ui_widgets); - Text::new( - "Welcome to the alpha version of Veloren!\n\ - \n\ - \n\ - Before you dive into the fun, please keep a few things in mind:\n\ - \n\ - - This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features. \n\ - \n\ - -If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.\n\ - \n\ - - Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however you wish \n\ - (provided derived work is also under GPL 3). - \n\ - - Veloren is a non-profit community project, and everybody working on it is a volunteer.\n\ - If you like what you see, you're welcome to join the development or art teams! - \n\ - - 'Voxel RPG' is a genre in its own right. First-person shooters used to be called Doom clones.\n\ - Like them, we're trying to build a niche. This game is not a clone, and its development will diverge from existing games in the future.\n\ - \n\ - Thanks for taking the time to read this notice, we hope you enjoy the game!\n\ - \n\ - ~ The Veloren Devs") - .top_left_with_margins_on(self.ids.disc_window, 110.0, 40.0) - .font_size(26) - .font_id(self.fonts.cyri) - .color(TEXT_COLOR) - .set(self.ids.disc_text_2, ui_widgets); + // Popup (Error/Info) + if let Some(popup_data) = &self.popup { + let text = Text::new(&popup_data.msg) + .rgba(1.0, 1.0, 1.0, if self.connect { fade_msg } else { 1.0 }) + .font_id(self.fonts.cyri); + Rectangle::fill_with([65.0 * 6.0, 140.0], color::TRANSPARENT) + .rgba(0.1, 0.1, 0.1, if self.connect { 0.0 } else { 1.0 }) + .parent(ui_widgets.window) + .up_from(self.ids.banner_top, 15.0) + .set(self.ids.login_error_bg, ui_widgets); + Image::new(self.imgs.info_frame) + .w_h(65.0 * 6.0, 140.0) + .color(Some(Color::Rgba( + 1.0, + 1.0, + 1.0, + if self.connect { 0.0 } else { 1.0 }, + ))) + .middle_of(self.ids.login_error_bg) + .set(self.ids.error_frame, ui_widgets); + if self.connect { + text.mid_top_with_margin_on(self.ids.error_frame, 10.0) + .font_id(self.fonts.alkhemi) + .bottom_left_with_margins_on(ui_widgets.window, 60.0, 60.0) + .font_size(70) + .set(self.ids.login_error, ui_widgets); + } else { + text.mid_top_with_margin_on(self.ids.error_frame, 10.0) + .font_id(self.fonts.cyri) + .font_size(25) + .set(self.ids.login_error, ui_widgets); + }; if Button::image(self.imgs.button) - .w_h(300.0, 50.0) - .mid_bottom_with_margin_on(self.ids.disc_window, 30.0) + .w_h(100.0, 30.0) + .mid_bottom_with_margin_on( + if self.connect { + ui_widgets.window + } else { + self.ids.login_error_bg + }, + 10.0, + ) .hover_image(self.imgs.button_hover) .press_image(self.imgs.button_press) .label_y(Relative::Scalar(2.0)) - .label("Accept") - .label_font_size(22) - .label_color(TEXT_COLOR) + .label(&popup_data.button_text) .label_font_id(self.fonts.cyri) - .set(self.ids.disc_button, ui_widgets) + .label_font_size(15) + .label_color(TEXT_COLOR) + .set(self.ids.button_ok, ui_widgets) .was_clicked() { - self.show_disclaimer = false; - events.push(Event::DisclaimerClosed); - } - } else { - // TODO: Don't use macros for this? - // Input fields - // Used when the login button is pressed, or enter is pressed within input field - macro_rules! login { - () => { - self.connecting = Some(std::time::Instant::now()); - self.popup = Some(PopupData { - msg: "Connecting...".to_string(), - button_text: "Cancel".to_string(), - popup_type: PopupType::ConnectionInfo, - }); - events.push(Event::LoginAttempt { - username: self.username.clone(), - password: self.password.clone(), - server_address: self.server_address.clone(), - }); + match popup_data.popup_type { + PopupType::ConnectionInfo => { + events.push(Event::CancelLoginAttempt); + } + _ => (), }; - } - // Info Window - Rectangle::fill_with([550.0, 200.0], color::BLACK) - .top_left_with_margins_on(ui_widgets.window, 40.0, 40.0) - .color(Color::Rgba(0.0, 0.0, 0.0, 0.95)) - .set(self.ids.info_frame, ui_widgets); - Image::new(self.imgs.banner_bottom) - .mid_bottom_with_margin_on(self.ids.info_frame, -50.0) - .w_h(550.0, 50.0) - .color(Some(Color::Rgba(0.0, 0.0, 0.0, 0.95))) - .set(self.ids.info_bottom, ui_widgets); - Text::new(intro_text) - .top_left_with_margins_on(self.ids.info_frame, 15.0, 15.0) - .font_size(20) - .font_id(self.fonts.cyri) - .color(TEXT_COLOR) - .set(self.ids.info_text, ui_widgets); + self.popup = None; + }; + } + if !self.connect { + Image::new(self.imgs.banner) + .w_h(65.0 * 6.0, 100.0 * 6.0) + .middle_of(self.ids.bg) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.9))) + .set(self.ids.banner, ui_widgets); - // Singleplayer - // Used when the singleplayer button is pressed - #[cfg(feature = "singleplayer")] - macro_rules! singleplayer { - () => { - events.push(Event::StartSingleplayer); - self.connecting = Some(std::time::Instant::now()); - self.popup = Some(PopupData { - msg: "Connecting...".to_string(), - button_text: "Cancel".to_string(), - popup_type: PopupType::ConnectionInfo, - }); - }; - } + Image::new(self.imgs.banner_top) + .w_h(65.0 * 6.0, 1.0 * 6.0) + .mid_top_with_margin_on(self.ids.banner, 0.0) + .set(self.ids.banner_top, ui_widgets); - // Username - Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) - .mid_top_with_margin_on(self.ids.banner_top, 160.0) - .set(self.ids.usrnm_bg, ui_widgets); - Image::new(self.imgs.input_bg) - .w_h(337.0, 67.0) - .middle_of(self.ids.usrnm_bg) - .set(self.ids.username_bg, ui_widgets); - for event in TextBox::new(&self.username) - .w_h(290.0, 30.0) - .mid_bottom_with_margin_on(self.ids.username_bg, 44.0 / 2.0) - .font_size(22) - .font_id(self.fonts.cyri) - .text_color(TEXT_COLOR) - // transparent background - .color(TRANSPARENT) - .border_color(TRANSPARENT) - .set(self.ids.username_field, ui_widgets) - { - match event { - TextBoxEvent::Update(username) => { - // Note: TextBox limits the input string length to what fits in it - self.username = username.to_string(); - } - TextBoxEvent::Enter => { - login!(); - } - } - } - // Password - // TODO: REACTIVATE THIS WHEN A PROPER ACCOUNT SYSTEM IS IN PLACE - /*Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) - .down_from(self.ids.usrnm_bg, 30.0) - .set(self.ids.passwd_bg, ui_widgets); - Image::new(self.imgs.input_bg) - .w_h(337.0, 67.0) - .middle_of(self.ids.passwd_bg) - .color(Some(INACTIVE)) - .set(self.ids.password_bg, ui_widgets); - for event in TextBox::new(&self.password) - .w_h(290.0, 30.0) - .mid_bottom_with_margin_on(self.ids.password_bg, 44.0 / 2.0) - .font_size(22) - .font_id(self.fonts.cyri) - .text_color(TEXT_COLOR) - // transparent background - .color(TRANSPARENT) - .border_color(TRANSPARENT) - .set(self.ids.password_field, ui_widgets) - { - match event { - TextBoxEvent::Update(password) => { - // Note: TextBox limits the input string length to what fits in it - self.password = password; - } - TextBoxEvent::Enter => { - login!(); - } - } - }*/ - // Popup (Error/Info) - if let Some(popup_data) = &self.popup { - let text = Text::new(&popup_data.msg) - .rgba(1.0, 1.0, 1.0, 1.0) - .font_size(25) - .font_id(self.fonts.cyri); - Rectangle::fill_with([65.0 * 6.0, 140.0], color::TRANSPARENT) - .rgba(0.1, 0.1, 0.1, 1.0) - .parent(ui_widgets.window) - .up_from(self.ids.banner_top, 15.0) - .set(self.ids.login_error_bg, ui_widgets); - Image::new(self.imgs.info_frame) - .w_h(65.0 * 6.0, 140.0) - .middle_of(self.ids.login_error_bg) - .set(self.ids.error_frame, ui_widgets); - text.mid_top_with_margin_on(self.ids.error_frame, 10.0) - .set(self.ids.login_error, ui_widgets); + // Logo + Image::new(self.imgs.v_logo) + .w_h(123.0 * 2.5, 35.0 * 2.5) + .mid_top_with_margin_on(self.ids.banner_top, 40.0) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.95))) + .set(self.ids.v_logo, ui_widgets); + + if self.show_disclaimer { + Image::new(self.imgs.disclaimer) + .w_h(1800.0, 800.0) + .middle_of(ui_widgets.window) + .scroll_kids() + .scroll_kids_vertically() + .set(self.ids.disc_window, ui_widgets); + + Text::new("Disclaimer") + .top_left_with_margins_on(self.ids.disc_window, 30.0, 40.0) + .font_size(35) + .font_id(self.fonts.alkhemi) + .color(TEXT_COLOR) + .set(self.ids.disc_text_1, ui_widgets); + Text::new( + "Welcome to the alpha version of Veloren!\n\ + \n\ + \n\ + Before you dive into the fun, please keep a few things in mind:\n\ + \n\ + - This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features. \n\ + \n\ + -If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.\n\ + \n\ + - Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however you wish \n\ + (provided derived work is also under GPL 3). + \n\ + - Veloren is a non-profit community project, and everybody working on it is a volunteer.\n\ + If you like what you see, you're welcome to join the development or art teams! + \n\ + - 'Voxel RPG' is a genre in its own right. First-person shooters used to be called Doom clones.\n\ + Like them, we're trying to build a niche. This game is not a clone, and its development will diverge from existing games in the future.\n\ + \n\ + Thanks for taking the time to read this notice, we hope you enjoy the game!\n\ + \n\ + ~ The Veloren Devs") + .top_left_with_margins_on(self.ids.disc_window, 110.0, 40.0) + .font_size(26) + .font_id(self.fonts.cyri) + .color(TEXT_COLOR) + .set(self.ids.disc_text_2, ui_widgets); if Button::image(self.imgs.button) - .w_h(100.0, 30.0) - .mid_bottom_with_margin_on(self.ids.login_error_bg, 10.0) + .w_h(300.0, 50.0) + .mid_bottom_with_margin_on(self.ids.disc_window, 30.0) .hover_image(self.imgs.button_hover) .press_image(self.imgs.button_press) .label_y(Relative::Scalar(2.0)) - .label(&popup_data.button_text) - .label_font_id(self.fonts.cyri) - .label_font_size(15) + .label("Accept") + .label_font_size(22) .label_color(TEXT_COLOR) - .set(self.ids.button_ok, ui_widgets) + .label_font_id(self.fonts.cyri) + .set(self.ids.disc_button, ui_widgets) .was_clicked() { - match popup_data.popup_type { - PopupType::ConnectionInfo => { - events.push(Event::CancelLoginAttempt); - } - _ => (), + self.show_disclaimer = false; + events.push(Event::DisclaimerClosed); + } + } else { + // TODO: Don't use macros for this? + // Input fields + // Used when the login button is pressed, or enter is pressed within input field + macro_rules! login { + () => { + self.connect = true; + self.connecting = Some(std::time::Instant::now()); + self.popup = Some(PopupData { + msg: "Connecting...".to_string(), + button_text: "Cancel".to_string(), + popup_type: PopupType::ConnectionInfo, + }); + + events.push(Event::LoginAttempt { + username: self.username.clone(), + password: self.password.clone(), + server_address: self.server_address.clone(), + }); }; - self.popup = None; - }; - } - if self.show_servers { - Image::new(self.imgs.info_frame) - .mid_top_with_margin_on(self.ids.username_bg, -320.0) - .w_h(400.0, 300.0) - .set(self.ids.servers_frame, ui_widgets); + } + // Info Window + Rectangle::fill_with([550.0, 200.0], color::BLACK) + .top_left_with_margins_on(ui_widgets.window, 40.0, 40.0) + .color(Color::Rgba(0.0, 0.0, 0.0, 0.95)) + .set(self.ids.info_frame, ui_widgets); + Image::new(self.imgs.banner_bottom) + .mid_bottom_with_margin_on(self.ids.info_frame, -50.0) + .w_h(550.0, 50.0) + .color(Some(Color::Rgba(0.0, 0.0, 0.0, 0.95))) + .set(self.ids.info_bottom, ui_widgets); + Text::new(intro_text) + .top_left_with_margins_on(self.ids.info_frame, 15.0, 15.0) + .font_size(20) + .font_id(self.fonts.cyri) + .color(TEXT_COLOR) + .set(self.ids.info_text, ui_widgets); - let ref mut net_settings = global_state.settings.networking; + // Singleplayer + // Used when the singleplayer button is pressed + #[cfg(feature = "singleplayer")] + macro_rules! singleplayer { + () => { + events.push(Event::StartSingleplayer); + self.connect = true; + self.connecting = Some(std::time::Instant::now()); + self.popup = Some(PopupData { + msg: "Creating World...".to_string(), + button_text: "Cancel".to_string(), + popup_type: PopupType::ConnectionInfo, + }); + }; + } - // TODO: Draw scroll bar or remove it. - let (mut items, _scrollbar) = List::flow_down(net_settings.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 &net_settings.servers[item.i] == &self.server_address { - text.push_str("-> ") - } else { - text.push_str(" ") + // Username + Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) + .mid_top_with_margin_on(self.ids.banner_top, 160.0) + .set(self.ids.usrnm_bg, ui_widgets); + Image::new(self.imgs.input_bg) + .w_h(337.0, 67.0) + .middle_of(self.ids.usrnm_bg) + .set(self.ids.username_bg, ui_widgets); + for event in TextBox::new(&self.username) + .w_h(290.0, 30.0) + .mid_bottom_with_margin_on(self.ids.username_bg, 44.0 / 2.0) + .font_size(22) + .font_id(self.fonts.cyri) + .text_color(TEXT_COLOR) + // transparent background + .color(TRANSPARENT) + .border_color(TRANSPARENT) + .set(self.ids.username_field, ui_widgets) + { + match event { + TextBoxEvent::Update(username) => { + // Note: TextBox limits the input string length to what fits in it + self.username = username.to_string(); + } + TextBoxEvent::Enter => { + login!(); + } } - text.push_str(&net_settings.servers[item.i]); + } + // Password + // TODO: REACTIVATE THIS WHEN A PROPER ACCOUNT SYSTEM IS IN PLACE + /*Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) + .down_from(self.ids.usrnm_bg, 30.0) + .set(self.ids.passwd_bg, ui_widgets); + Image::new(self.imgs.input_bg) + .w_h(337.0, 67.0) + .middle_of(self.ids.passwd_bg) + .color(Some(INACTIVE)) + .set(self.ids.password_bg, ui_widgets); + for event in TextBox::new(&self.password) + .w_h(290.0, 30.0) + .mid_bottom_with_margin_on(self.ids.password_bg, 44.0 / 2.0) + .font_size(22) + .font_id(self.fonts.cyri) + .text_color(TEXT_COLOR) + // transparent background + .color(TRANSPARENT) + .border_color(TRANSPARENT) + .set(self.ids.password_field, ui_widgets) + { + match event { + TextBoxEvent::Update(password) => { + // Note: TextBox limits the input string length to what fits in it + self.password = password; + } + TextBoxEvent::Enter => { + login!(); + } + } + }*/ + if self.show_servers { + Image::new(self.imgs.info_frame) + .mid_top_with_margin_on(self.ids.username_bg, -320.0) + .w_h(400.0, 300.0) + .set(self.ids.servers_frame, ui_widgets); - if item - .set( - Button::image(self.imgs.nothing) - .w_h(100.0, 50.0) - .mid_top_with_margin_on(self.ids.servers_frame, 10.0) - //.hover_image(self.imgs.button_hover) - //.press_image(self.imgs.button_press) - .label_y(Relative::Scalar(2.0)) - .label(&text) - .label_font_size(20) - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR), - ui_widgets, - ) + let ref mut net_settings = global_state.settings.networking; + + // TODO: Draw scroll bar or remove it. + let (mut items, _scrollbar) = List::flow_down(net_settings.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 &net_settings.servers[item.i] == &self.server_address { + text.push_str("-> ") + } else { + text.push_str(" ") + } + text.push_str(&net_settings.servers[item.i]); + + if item + .set( + Button::image(self.imgs.nothing) + .w_h(100.0, 50.0) + .mid_top_with_margin_on(self.ids.servers_frame, 10.0) + //.hover_image(self.imgs.button_hover) + //.press_image(self.imgs.button_press) + .label_y(Relative::Scalar(2.0)) + .label(&text) + .label_font_size(20) + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR), + ui_widgets, + ) + .was_clicked() + { + self.server_address = net_settings.servers[item.i].clone(); + net_settings.default_server = item.i; + } + } + + if Button::image(self.imgs.button) + .w_h(200.0, 53.0) + .mid_bottom_with_margin_on(self.ids.servers_frame, 5.0) + .hover_image(self.imgs.button_hover) + .press_image(self.imgs.button_press) + .label_y(Relative::Scalar(2.0)) + .label("Close") + .label_font_size(20) + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR) + .set(self.ids.servers_close, ui_widgets) .was_clicked() { - self.server_address = net_settings.servers[item.i].clone(); - net_settings.default_server = item.i; - } + self.show_servers = false + }; } - - if Button::image(self.imgs.button) - .w_h(200.0, 53.0) - .mid_bottom_with_margin_on(self.ids.servers_frame, 5.0) - .hover_image(self.imgs.button_hover) - .press_image(self.imgs.button_press) - .label_y(Relative::Scalar(2.0)) - .label("Close") - .label_font_size(20) - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR) - .set(self.ids.servers_close, ui_widgets) - .was_clicked() + // Server address + Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) + .down_from(self.ids.usrnm_bg, 30.0) + .set(self.ids.srvr_bg, ui_widgets); + Image::new(self.imgs.input_bg) + .w_h(337.0, 67.0) + .middle_of(self.ids.srvr_bg) + .set(self.ids.address_bg, ui_widgets); + for event in TextBox::new(&self.server_address) + .w_h(290.0, 30.0) + .mid_bottom_with_margin_on(self.ids.address_bg, 44.0 / 2.0) + .font_size(22) + .font_id(self.fonts.cyri) + .text_color(TEXT_COLOR) + // transparent background + .color(TRANSPARENT) + .border_color(TRANSPARENT) + .set(self.ids.address_field, ui_widgets) { - self.show_servers = false - }; - } - // Server address - Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) - .down_from(self.ids.usrnm_bg, 30.0) - .set(self.ids.srvr_bg, ui_widgets); - Image::new(self.imgs.input_bg) - .w_h(337.0, 67.0) - .middle_of(self.ids.srvr_bg) - .set(self.ids.address_bg, ui_widgets); - for event in TextBox::new(&self.server_address) - .w_h(290.0, 30.0) - .mid_bottom_with_margin_on(self.ids.address_bg, 44.0 / 2.0) - .font_size(22) - .font_id(self.fonts.cyri) - .text_color(TEXT_COLOR) - // transparent background - .color(TRANSPARENT) - .border_color(TRANSPARENT) - .set(self.ids.address_field, ui_widgets) - { - match event { - TextBoxEvent::Update(server_address) => { - self.server_address = server_address.to_string(); - } - TextBoxEvent::Enter => { - login!(); + match event { + TextBoxEvent::Update(server_address) => { + self.server_address = server_address.to_string(); + } + TextBoxEvent::Enter => { + login!(); + } } } - } - // Login button - if Button::image(self.imgs.button) - .hover_image(self.imgs.button_hover) - .press_image(self.imgs.button_press) - .w_h(258.0, 55.0) - .down_from(self.ids.address_bg, 20.0) - .align_middle_x_of(self.ids.address_bg) - .label("Multiplayer") - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR) - .label_font_size(22) - .label_y(Relative::Scalar(5.0)) - /*.with_tooltip( - tooltip_manager, - "Login", - "Click to login with the entered details", - &tooltip, - ) - .tooltip_image(self.imgs.v_logo)*/ - .set(self.ids.login_button, ui_widgets) - .was_clicked() - { - login!(); - } - - // Singleplayer button - #[cfg(feature = "singleplayer")] - { + // Login button if Button::image(self.imgs.button) .hover_image(self.imgs.button_hover) .press_image(self.imgs.button_press) .w_h(258.0, 55.0) - .down_from(self.ids.login_button, 20.0) + .down_from(self.ids.address_bg, 20.0) .align_middle_x_of(self.ids.address_bg) - .label("Singleplayer") + .label("Multiplayer") .label_font_id(self.fonts.cyri) .label_color(TEXT_COLOR) .label_font_size(22) .label_y(Relative::Scalar(5.0)) - .label_x(Relative::Scalar(2.0)) - .set(self.ids.singleplayer_button, ui_widgets) + /*.with_tooltip( + tooltip_manager, + "Login", + "Click to login with the entered details", + &tooltip, + ) + .tooltip_image(self.imgs.v_logo)*/ + .set(self.ids.login_button, ui_widgets) .was_clicked() { - singleplayer!(); + login!(); } - } - // Quit - if Button::image(self.imgs.button) - .w_h(190.0, 40.0) - .bottom_left_with_margins_on(ui_widgets.window, 60.0, 30.0) - .hover_image(self.imgs.button_hover) - .press_image(self.imgs.button_press) - .label("Quit") - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR) - .label_font_size(20) - .label_y(Relative::Scalar(3.0)) - .set(self.ids.quit_button, ui_widgets) - .was_clicked() - { - events.push(Event::Quit); - } - // Settings - if Button::image(self.imgs.button) - .w_h(190.0, 40.0) - .up_from(self.ids.quit_button, 8.0) - //.hover_image(self.imgs.button_hover) - //.press_image(self.imgs.button_press) - .label("Settings") - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR_2) - .label_font_size(20) - .label_y(Relative::Scalar(3.0)) - .set(self.ids.settings_button, ui_widgets) - .was_clicked() - { - events.push(Event::Settings); - } + // Singleplayer button + #[cfg(feature = "singleplayer")] + { + if Button::image(self.imgs.button) + .hover_image(self.imgs.button_hover) + .press_image(self.imgs.button_press) + .w_h(258.0, 55.0) + .down_from(self.ids.login_button, 20.0) + .align_middle_x_of(self.ids.address_bg) + .label("Singleplayer") + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR) + .label_font_size(22) + .label_y(Relative::Scalar(5.0)) + .label_x(Relative::Scalar(2.0)) + .set(self.ids.singleplayer_button, ui_widgets) + .was_clicked() + { + singleplayer!(); + } + } + // Quit + if Button::image(self.imgs.button) + .w_h(190.0, 40.0) + .bottom_left_with_margins_on(ui_widgets.window, 60.0, 30.0) + .hover_image(self.imgs.button_hover) + .press_image(self.imgs.button_press) + .label("Quit") + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR) + .label_font_size(20) + .label_y(Relative::Scalar(3.0)) + .set(self.ids.quit_button, ui_widgets) + .was_clicked() + { + events.push(Event::Quit); + } - // Servers - if Button::image(self.imgs.button) - .w_h(190.0, 40.0) - .up_from(self.ids.settings_button, 8.0) - .hover_image(self.imgs.button_hover) - .press_image(self.imgs.button_press) - .label("Servers") - .label_font_id(self.fonts.cyri) - .label_color(TEXT_COLOR) - .label_font_size(20) - .label_y(Relative::Scalar(3.0)) - .set(self.ids.servers_button, ui_widgets) - .was_clicked() - { - self.show_servers = !self.show_servers; - }; + // Settings + if Button::image(self.imgs.button) + .w_h(190.0, 40.0) + .up_from(self.ids.quit_button, 8.0) + //.hover_image(self.imgs.button_hover) + //.press_image(self.imgs.button_press) + .label("Settings") + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR_2) + .label_font_size(20) + .label_y(Relative::Scalar(3.0)) + .set(self.ids.settings_button, ui_widgets) + .was_clicked() + { + events.push(Event::Settings); + } + + // Servers + if Button::image(self.imgs.button) + .w_h(190.0, 40.0) + .up_from(self.ids.settings_button, 8.0) + .hover_image(self.imgs.button_hover) + .press_image(self.imgs.button_press) + .label("Servers") + .label_font_id(self.fonts.cyri) + .label_color(TEXT_COLOR) + .label_font_size(20) + .label_y(Relative::Scalar(3.0)) + .set(self.ids.servers_button, ui_widgets) + .was_clicked() + { + self.show_servers = !self.show_servers; + }; + } } events @@ -657,24 +691,27 @@ impl MainMenuUi { popup_type: PopupType::Error, }); self.connecting = None; + self.connect = false; } pub fn connected(&mut self) { self.popup = None; self.connecting = None; + self.connect = false; } pub fn cancel_connection(&mut self) { self.popup = None; self.connecting = None; + self.connect = false; } pub fn handle_event(&mut self, event: ui::Event) { self.ui.handle_event(event); } - pub fn maintain(&mut self, global_state: &mut GlobalState) -> Vec { - let events = self.update_layout(global_state); + pub fn maintain(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec { + let events = self.update_layout(global_state, dt); self.ui.maintain(global_state.window.renderer_mut(), None); events }