diff --git a/assets/voxygen/element/buttons/social_tab_active.png b/assets/voxygen/element/buttons/social_tab_active.png new file mode 100644 index 0000000000..0d9660f931 Binary files /dev/null and b/assets/voxygen/element/buttons/social_tab_active.png differ diff --git a/assets/voxygen/element/buttons/social_tab_inactive.png b/assets/voxygen/element/buttons/social_tab_inactive.png new file mode 100644 index 0000000000..d096642b4f Binary files /dev/null and b/assets/voxygen/element/buttons/social_tab_inactive.png differ diff --git a/assets/voxygen/i18n/en.ron b/assets/voxygen/i18n/en.ron index bc70ccabb6..302d545d7c 100644 --- a/assets/voxygen/i18n/en.ron +++ b/assets/voxygen/i18n/en.ron @@ -308,11 +308,15 @@ magically infused items?"#, "hud.settings.reset_keybinds": "Reset to Defaults", "hud.social": "Social", - "hud.social.online": "Online", + "hud.social.online": "Online:", "hud.social.friends": "Friends", "hud.social.not_yet_available": "Not yet available", "hud.social.faction": "Faction", "hud.social.play_online_fmt": "{nb_player} player(s) online", + "hud.social.name": "Name", + "hud.social.level": "Level", + "hud.social.zone": "Zone", + "hud.crafting": "Crafting", "hud.crafting.recipes": "Recipes", diff --git a/assets/world/structure/dungeon/misc_entrance/tower-ruin.vox b/assets/world/structure/dungeon/misc_entrance/tower-ruin.vox index 95a0d5c58f..8b681c8f91 100644 Binary files a/assets/world/structure/dungeon/misc_entrance/tower-ruin.vox and b/assets/world/structure/dungeon/misc_entrance/tower-ruin.vox differ diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 4bf4298999..79eda06010 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -59,14 +59,18 @@ image_ids! { selection_press: "voxygen.element.frames.selection_press", // Social Window - social_button: "voxygen.element.buttons.social_tab", - social_button_pressed: "voxygen.element.buttons.social_tab_pressed", - social_button_hover: "voxygen.element.buttons.social_tab_hover", - social_button_press: "voxygen.element.buttons.social_tab_press", - social_frame: "voxygen.element.frames.social_frame", + social_frame_on: "voxygen.element.misc_bg.social_frame", + social_bg_on: "voxygen.element.misc_bg.social_bg", + social_frame_friends: "voxygen.element.misc_bg.social_frame", + social_bg_friends: "voxygen.element.misc_bg.social_bg", + social_frame_fact: "voxygen.element.misc_bg.social_frame", + social_bg_fact: "voxygen.element.misc_bg.social_bg", + social_tab_act: "voxygen.element.buttons.social_tab_active", + social_tab_inact: "voxygen.element.buttons.social_tab_inactive", + social_tab_inact_hover: "voxygen.element.buttons.social_tab_inactive", + social_tab_inact_press: "voxygen.element.buttons.social_tab_inactive", // Crafting Window - crafting_window: "voxygen.element.misc_bg.crafting", crafting_frame: "voxygen.element.misc_bg.crafting_frame", crafting_icon_bordered: "voxygen.element.icons.anvil", @@ -75,7 +79,6 @@ image_ids! { crafting_icon_press: "voxygen.element.buttons.anvil_press", // Group Window - member_frame: "voxygen.element.frames.group_member_frame", member_bg: "voxygen.element.frames.group_member_bg", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index e09d26ce34..ab485be37c 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1924,22 +1924,28 @@ impl Hud { // Social Window if self.show.social { - for event in Social::new( - &self.show, - client, - &self.imgs, - &self.fonts, - &self.voxygen_i18n, - info.selected_entity, - ) - .set(self.ids.social_window, ui_widgets) - { - match event { - social::Event::Close => self.show.social(false), - social::Event::ChangeSocialTab(social_tab) => { - self.show.open_social_tab(social_tab) - }, - social::Event::Invite(uid) => events.push(Event::InviteMember(uid)), + let ecs = client.state().ecs(); + let stats = ecs.read_storage::(); + let me = client.entity(); + if let Some(stats) = stats.get(me) { + for event in Social::new( + &self.show, + client, + &self.imgs, + &self.fonts, + &self.voxygen_i18n, + &stats, + info.selected_entity, + ) + .set(self.ids.social_window, ui_widgets) + { + match event { + social::Event::Close => self.show.social(false), + social::Event::ChangeSocialTab(social_tab) => { + self.show.open_social_tab(social_tab) + }, + social::Event::Invite(uid) => events.push(Event::InviteMember(uid)), + } } } } diff --git a/voxygen/src/hud/social.rs b/voxygen/src/hud/social.rs index 49f840fd9e..06e846e5f1 100644 --- a/voxygen/src/hud/social.rs +++ b/voxygen/src/hud/social.rs @@ -1,32 +1,43 @@ -use super::{img_ids::Imgs, Show, TEXT_COLOR, TEXT_COLOR_3, UI_MAIN}; +use super::{img_ids::Imgs, Show, TEXT_COLOR, TEXT_COLOR_3, UI_HIGHLIGHT_0, UI_MAIN}; use crate::{i18n::VoxygenLocalization, ui::fonts::ConrodVoxygenFonts}; use client::{self, Client}; -use common::sync::Uid; +use common::{comp::Stats, sync::Uid}; use conrod_core::{ color, widget::{self, Button, Image, Rectangle, Scrollbar, Text}, - widget_ids, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, + widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; use std::time::Instant; widget_ids! { pub struct Ids { - social_frame, - social_close, - social_title, frame, - align, - content_align, - online_tab, - friends_tab, - faction_tab, - online_title, - online_no, + close, + title, + bg, + icon, scrollbar, + online_align, + online_tab, + online_tab_icon, + names_align, + name_txt, + player_levels[], + player_names[], + player_zones[], + online_txt, + online_no, + levels_align, + level_txt, + zones_align, + zone_txt, + friends_tab, + //friends_tab_icon, + faction_tab, + //faction_tab_icon, friends_test, faction_test, - player_names[], invite_button, } } @@ -51,6 +62,7 @@ pub struct Social<'a> { imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, localized_strings: &'a std::sync::Arc, + stats: &'a Stats, selected_entity: Option<(specs::Entity, Instant)>, @@ -65,6 +77,7 @@ impl<'a> Social<'a> { imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, localized_strings: &'a std::sync::Arc, + stats: &'a Stats, selected_entity: Option<(specs::Entity, Instant)>, ) -> Self { Self { @@ -73,6 +86,7 @@ impl<'a> Social<'a> { imgs, fonts, localized_strings, + stats, selected_entity, common: widget::CommonBuilder::default(), } @@ -105,21 +119,41 @@ impl<'a> Widget for Social<'a> { let mut events = Vec::new(); + // Window frame and BG let pos = if self.show.group { 180.0 } else { 25.0 }; - - Image::new(self.imgs.window_3) + // TODO: Different window visuals depending on the selected tab + let window_bg = match &self.show.social_tab { + SocialTab::Online => self.imgs.social_bg_on, + SocialTab::Friends => self.imgs.social_bg_friends, + SocialTab::Faction => self.imgs.social_bg_fact, + }; + let window_frame = match &self.show.social_tab { + SocialTab::Online => self.imgs.social_frame_on, + SocialTab::Friends => self.imgs.social_frame_friends, + SocialTab::Faction => self.imgs.social_frame_fact, + }; + Image::new(window_bg) .top_left_with_margins_on(ui.window, 200.0, pos) .color(Some(UI_MAIN)) - .w_h(103.0 * 4.0, 122.0 * 4.0) - .set(state.ids.social_frame, ui); - + .w_h(280.0, 460.0) + .set(state.ids.bg, ui); + Image::new(window_frame) + .middle_of(state.ids.bg) + .color(Some(UI_HIGHLIGHT_0)) + .w_h(280.0, 460.0) + .set(state.ids.frame, ui); + // Icon + Image::new(self.imgs.social) + .w_h(30.0, 30.0) + .top_left_with_margins_on(state.ids.frame, 6.0, 6.0) + .set(state.ids.icon, ui); // X-Button if Button::image(self.imgs.close_button) - .w_h(28.0, 28.0) + .w_h(24.0, 25.0) .hover_image(self.imgs.close_button_hover) .press_image(self.imgs.close_button_press) - .top_right_with_margins_on(state.ids.social_frame, 0.0, 0.0) - .set(state.ids.social_close, ui) + .top_right_with_margins_on(state.ids.frame, 0.0, 0.0) + .set(state.ids.close, ui) .was_clicked() { events.push(Event::Close); @@ -127,63 +161,324 @@ impl<'a> Widget for Social<'a> { // Title Text::new(&self.localized_strings.get("hud.social")) - .mid_top_with_margin_on(state.ids.social_frame, 6.0) + .mid_top_with_margin_on(state.ids.frame, 9.0) .font_id(self.fonts.cyri.conrod_id) - .font_size(self.fonts.cyri.scale(14)) + .font_size(self.fonts.cyri.scale(22)) .color(TEXT_COLOR) - .set(state.ids.social_title, ui); + .set(state.ids.title, ui); - // Alignment - Rectangle::fill_with([99.0 * 4.0, 112.0 * 4.0], color::TRANSPARENT) - .mid_top_with_margin_on(state.ids.social_frame, 8.0 * 4.0) - .set(state.ids.align, ui); - // Content Alignment - Rectangle::fill_with([94.0 * 4.0, 94.0 * 4.0], color::TRANSPARENT) - .middle_of(state.ids.frame) - .scroll_kids() - .scroll_kids_vertically() - .set(state.ids.content_align, ui); - Scrollbar::y_axis(state.ids.content_align) - .thickness(5.0) - .rgba(0.33, 0.33, 0.33, 1.0) - .set(state.ids.scrollbar, ui); - // Frame - Image::new(self.imgs.social_frame) - .w_h(99.0 * 4.0, 100.0 * 4.0) - .mid_bottom_of(state.ids.align) - .color(Some(UI_MAIN)) - .set(state.ids.frame, ui); - - // Online Tab - - if Button::image(if let SocialTab::Online = self.show.social_tab { - self.imgs.social_button_pressed - } else { - self.imgs.social_button + // Tabs Buttons + // Online Tab Button + if Button::image(match &self.show.social_tab { + SocialTab::Online => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact, }) - .w_h(30.0 * 4.0, 12.0 * 4.0) - .hover_image(if let SocialTab::Online = self.show.social_tab { - self.imgs.social_button_pressed - } else { - self.imgs.social_button_hover + .w_h(30.0, 44.0) + .hover_image(match &self.show.social_tab { + SocialTab::Online => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_hover, }) - .press_image(if let SocialTab::Online = self.show.social_tab { - self.imgs.social_button_pressed - } else { - self.imgs.social_button_press + .press_image(match &self.show.social_tab { + SocialTab::Online => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_press, }) - .top_left_with_margins_on(state.ids.align, 4.0, 0.0) - .label(&self.localized_strings.get("hud.social.online")) - .label_font_size(self.fonts.cyri.scale(14)) - .label_font_id(self.fonts.cyri.conrod_id) - .parent(state.ids.frame) - .color(UI_MAIN) - .label_color(TEXT_COLOR) + .image_color(match &self.show.social_tab { + SocialTab::Online => UI_MAIN, + _ => Color::Rgba(1.0, 1.0, 1.0, 0.6), + }) + .top_right_with_margins_on(state.ids.frame, 50.0, -28.0) .set(state.ids.online_tab, ui) .was_clicked() { events.push(Event::ChangeSocialTab(SocialTab::Online)); } + Image::new(self.imgs.chat_online_small) + .w_h(20.0, 20.0) + .top_right_with_margins_on(state.ids.online_tab, 12.0, 7.0) + .color(match &self.show.social_tab { + SocialTab::Online => Some(TEXT_COLOR), + _ => Some(UI_MAIN), + }) + .set(state.ids.online_tab_icon, ui); + // Friends Tab Button + if Button::image(match &self.show.social_tab { + SocialTab::Friends => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact, + }) + .w_h(30.0, 44.0) + .hover_image(match &self.show.social_tab { + SocialTab::Friends => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_hover, + }) + .press_image(match &self.show.social_tab { + SocialTab::Friends => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_press, + }) + .down_from(state.ids.online_tab, 0.0) + .image_color(match &self.show.social_tab { + SocialTab::Friends => UI_MAIN, + _ => Color::Rgba(1.0, 1.0, 1.0, 0.6), + }) + .set(state.ids.friends_tab, ui) + .was_clicked() + { + events.push(Event::ChangeSocialTab(SocialTab::Friends)); + } + // Faction Tab Button + if Button::image(match &self.show.social_tab { + SocialTab::Friends => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact, + }) + .w_h(30.0, 44.0) + .hover_image(match &self.show.social_tab { + SocialTab::Faction => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_hover, + }) + .press_image(match &self.show.social_tab { + SocialTab::Faction => self.imgs.social_tab_act, + _ => self.imgs.social_tab_inact_press, + }) + .down_from(state.ids.friends_tab, 0.0) + .image_color(match &self.show.social_tab { + SocialTab::Faction => UI_MAIN, + _ => Color::Rgba(1.0, 1.0, 1.0, 0.6), + }) + .set(state.ids.faction_tab, ui) + .was_clicked() + { + events.push(Event::ChangeSocialTab(SocialTab::Faction)); + } + // Online Tab + if let SocialTab::Online = self.show.social_tab { + // Content Alignments + Rectangle::fill_with([270.0, 346.0], color::TRANSPARENT) + .mid_top_with_margin_on(state.ids.frame, 74.0) + .scroll_kids_vertically() + .set(state.ids.online_align, ui); + Rectangle::fill_with([133.0, 370.0], color::TRANSPARENT) + .top_left_with_margins_on(state.ids.online_align, 0.0, 0.0) + .crop_kids() + .set(state.ids.names_align, ui); + Rectangle::fill_with([39.0, 370.0], color::TRANSPARENT) + .right_from(state.ids.names_align, 2.0) + .crop_kids() + .set(state.ids.levels_align, ui); + Rectangle::fill_with([94.0, 370.0], color::TRANSPARENT) + .right_from(state.ids.levels_align, 2.0) + .crop_kids() + .set(state.ids.zones_align, ui); + Scrollbar::y_axis(state.ids.online_align) + .thickness(4.0) + .color(UI_HIGHLIGHT_0) + .set(state.ids.scrollbar, ui); + // + // Headlines + // + if Button::image(self.imgs.nothing) + .w_h(133.0, 18.0) + .top_left_with_margins_on(state.ids.frame, 52.0, 7.0) + .label(&self.localized_strings.get("hud.social.name")) + .label_font_size(self.fonts.cyri.scale(14)) + .label_y(conrod_core::position::Relative::Scalar(0.0)) + .label_font_id(self.fonts.cyri.conrod_id) + .label_color(TEXT_COLOR) + .set(state.ids.name_txt, ui) + .was_clicked() + { + // Sort widgets by name alphabetically + } + if Button::image(self.imgs.nothing) + .w_h(39.0, 18.0) + .right_from(state.ids.name_txt, 2.0) + .label(&self.localized_strings.get("hud.social.level")) + .label_font_size(self.fonts.cyri.scale(14)) + .label_y(conrod_core::position::Relative::Scalar(0.0)) + .label_font_id(self.fonts.cyri.conrod_id) + .label_color(TEXT_COLOR) + .set(state.ids.level_txt, ui) + .was_clicked() + { + // Sort widgets by level (increasing) + } + if Button::image(self.imgs.nothing) + .w_h(93.0, 18.0) + .right_from(state.ids.level_txt, 2.0) + .label(&self.localized_strings.get("hud.social.zone")) + .label_font_size(self.fonts.cyri.scale(14)) + .label_y(conrod_core::position::Relative::Scalar(0.0)) + .label_font_id(self.fonts.cyri.conrod_id) + .label_color(TEXT_COLOR) + .set(state.ids.zone_txt, ui) + .was_clicked() + { + // Sort widgets by zone alphabetically + } + // Online Text + let players = self.client.player_list.iter().filter(|(_, p)| p.is_online); + let count = players.clone().count(); + Text::new(&self.localized_strings.get("hud.social.online")) + .bottom_left_with_margins_on(state.ids.frame, 18.0, 10.0) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(14)) + .color(TEXT_COLOR) + .set(state.ids.online_txt, ui); + Text::new(&count.to_string()) + .right_from(state.ids.online_txt, 5.0) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(14)) + .color(TEXT_COLOR) + .set(state.ids.online_no, ui); + // Adjust widget_id struct vec length to player count + if state.ids.player_levels.len() < count { + state.update(|s| { + s.ids + .player_levels + .resize(count, &mut ui.widget_id_generator()) + }) + }; + if state.ids.player_names.len() < count { + state.update(|s| { + s.ids + .player_names + .resize(count, &mut ui.widget_id_generator()) + }) + }; + if state.ids.player_zones.len() < count { + state.update(|s| { + s.ids + .player_zones + .resize(count, &mut ui.widget_id_generator()) + }) + }; + // Create a name, level and zone row for every player in the list + for (i, (&uid, player_info)) in players.enumerate() { + let selected = state.selected_uid.map_or(false, |u| u.0 == uid); + let alias = &player_info.player_alias; + let name = match &player_info.character { + Some(character) => format!("{} ", &character.name), + None => "".to_string(), // character select or spectating + }; + let level = match &player_info.character { + Some(character) => format!("{} ", &character.level), + None => "".to_string(), // character select or spectating + }; + let setting = true; // TODO Remove this + let zone = "Wilderness"; // TODO: Add real zone + let name_text = if name == self.stats.name { + format!("You ({})", name) // TODO: Locale + } else if setting { + format!("{}", name) + } else { + format!("[{}] {}", alias, name) + }; + // Player name widgets + let button = Button::image(if !selected { + self.imgs.nothing + } else { + self.imgs.selection + }); + let button = if i == 0 { + button.mid_top_with_margin_on(state.ids.names_align, 1.0) + } else { + button.down_from(state.ids.player_names[i - 1], 1.0) + }; + if button + .w_h(133.0, 20.0) + .hover_image(if selected { + self.imgs.selection + } else { + self.imgs.selection_hover + }) + .press_image(if selected { + self.imgs.selection + } else { + self.imgs.selection_press + }) + .label(&name_text) + .label_font_size(self.fonts.cyri.scale(14)) + .label_y(conrod_core::position::Relative::Scalar(0.0)) + .label_font_id(self.fonts.cyri.conrod_id) + .label_color(TEXT_COLOR) + .set(state.ids.player_names[i], ui) + .was_clicked() + {}; + let level_txt = if i == 0 { + Text::new(&level).mid_top_with_margin_on(state.ids.levels_align, 2.0) + } else { + Text::new(&level).down_from(state.ids.player_levels[i - 1], 2.0) + }; + level_txt + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.player_levels[i], ui); + let zone_txt = if i == 0 { + Text::new(&zone).mid_top_with_margin_on(state.ids.zones_align, 2.0) + } else { + Text::new(&zone).down_from(state.ids.player_zones[i - 1], 2.0) + }; + zone_txt + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.player_zones[i], ui); + + // Check for click + if ui + .widget_input(state.ids.player_names[i]) + .clicks() + .left() + .next() + .is_some() + { + state.update(|s| s.selected_uid = Some((uid, Instant::now()))); + } + let player = if name == self.stats.name { true } else { false }; + if Button::image(self.imgs.button) + .w_h(106.0, 26.0) + .bottom_right_with_margins_on(state.ids.frame, 9.0, 7.0) + .hover_image(if !player && selected { + self.imgs.button_hover + } else { + self.imgs.button + }) + .press_image(if !player && selected { + self.imgs.button_press + } else { + self.imgs.button + }) + .label(&self.localized_strings.get("hud.group.invite")) + .label_y(conrod_core::position::Relative::Scalar(3.0)) + .label_color(if !player && selected { + TEXT_COLOR + } else { + TEXT_COLOR_3 + }) + .image_color(if !player && selected { + TEXT_COLOR + } else { + TEXT_COLOR_3 + }) + .label_font_size(self.fonts.cyri.scale(15)) + .label_font_id(self.fonts.cyri.conrod_id) + .set(state.ids.invite_button, ui) + .was_clicked() + { + if !player && selected { + events.push(Event::Invite(uid)); + state.update(|s| { + s.selected_uid = None; + }); + } + } + } + // Invite Button + /* */ + } // End of Online Tab + + // Alignment + /* + // Online Tab // Contents @@ -362,7 +657,7 @@ impl<'a> Widget for Social<'a> { .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR_3) .set(state.ids.faction_test, ui); - } + }*/ events }