Added search to crafting and social windows, added i18n support to crafting tabs, fixed social window offset when group open, removed tabs in social window

This commit is contained in:
hqurve 2021-04-07 20:24:22 +00:00 committed by Ben Wallis
parent 60efd682e2
commit be42cc60c4
21 changed files with 664 additions and 653 deletions

View File

@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Crafting menu tabs - Crafting menu tabs
- Auto camera setting, making the game easier to play with one hand - Auto camera setting, making the game easier to play with one hand
- Topographic map option - Topographic map option
- Search bars for social and crafting window
### Changed ### Changed
@ -48,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added a raycast check to beams to prevent their effect applying through walls - Added a raycast check to beams to prevent their effect applying through walls
- Flying agents raycast more angles to check for obstacles. - Flying agents raycast more angles to check for obstacles.
- Mouse Cursor now locks to the center of the screen when menu is not open - Mouse Cursor now locks to the center of the screen when menu is not open
- Social window no longer moves when group is open
## [0.9.0] - 2021-03-20 ## [0.9.0] - 2021-03-20

BIN
assets/voxygen/element/buttons/search_btn.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/buttons/search_btn_hover.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/buttons/search_btn_press.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/voxygen/element/icons/globe.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/icons/globe_2.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -8,6 +8,18 @@
"hud.crafting.ingredients": "Ingredients:", "hud.crafting.ingredients": "Ingredients:",
"hud.crafting.craft": "Craft", "hud.crafting.craft": "Craft",
"hud.crafting.tool_cata": "Requires:", "hud.crafting.tool_cata": "Requires:",
// Tabs
"hud.crafting.tabs.all": "All",
"hud.crafting.tabs.armor": "Armor",
"hud.crafting.tabs.dismantle": "Dismantle",
"hud.crafting.tabs.food": "Food",
"hud.crafting.tabs.glider": "Gliders",
"hud.crafting.tabs.potion": "Potions",
"hud.crafting.tabs.tool": "Tools",
"hud.crafting.tabs.utility": "Utility",
"hud.crafting.tabs.weapon": "Weapons",
"hud.crafting.tabs.bag": "Bags",
}, },

View File

@ -22,8 +22,8 @@ use common::{
recipe::RecipeInput, recipe::RecipeInput,
}; };
use conrod_core::{ use conrod_core::{
color, color, image,
widget::{self, Button, Image, Rectangle, Scrollbar, Text}, widget::{self, Button, Image, Rectangle, Scrollbar, Text, TextEdit},
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -41,7 +41,13 @@ widget_ids! {
title_rec, title_rec,
align_rec, align_rec,
scrollbar_rec, scrollbar_rec,
btn_open_search,
btn_close_search,
input_search,
input_bg_search,
input_overlay_search,
title_ing, title_ing,
tags_ing[],
align_ing, align_ing,
scrollbar_ing, scrollbar_ing,
btn_craft, btn_craft,
@ -64,8 +70,10 @@ widget_ids! {
pub enum Event { pub enum Event {
CraftRecipe(String), CraftRecipe(String),
ChangeCraftingTab(SelectedCraftingTab), ChangeCraftingTab(CraftingTab),
Close, Close,
Focus(widget::Id),
SearchRecipe(Option<String>),
} }
#[derive(WidgetCommon)] #[derive(WidgetCommon)]
@ -120,7 +128,8 @@ impl<'a> Crafting<'a> {
} }
#[derive(Debug, EnumIter, PartialEq)] #[derive(Debug, EnumIter, PartialEq)]
pub enum SelectedCraftingTab { pub enum CraftingTab {
All,
Armor, Armor,
Weapon, Weapon,
Food, Food,
@ -131,6 +140,61 @@ pub enum SelectedCraftingTab {
Utility, Utility,
Glider, Glider,
} }
impl CraftingTab {
fn name_key(&self) -> &str {
match self {
CraftingTab::All => "hud.crafting.tabs.all",
CraftingTab::Armor => "hud.crafting.tabs.armor",
CraftingTab::Dismantle => "hud.crafting.tabs.dismantle",
CraftingTab::Food => "hud.crafting.tabs.food",
CraftingTab::Glider => "hud.crafting.tabs.glider",
CraftingTab::Potion => "hud.crafting.tabs.potion",
CraftingTab::Tool => "hud.crafting.tabs.tool",
CraftingTab::Utility => "hud.crafting.tabs.utility",
CraftingTab::Weapon => "hud.crafting.tabs.weapon",
CraftingTab::Bag => "hud.crafting.tabs.bag",
}
}
fn img_id(&self, imgs: &Imgs) -> image::Id {
match self {
CraftingTab::All => imgs.icon_globe,
CraftingTab::Armor => imgs.icon_armor,
CraftingTab::Dismantle => imgs.icon_dismantle,
CraftingTab::Food => imgs.icon_food,
CraftingTab::Glider => imgs.icon_glider,
CraftingTab::Potion => imgs.icon_potion,
CraftingTab::Tool => imgs.icon_tools,
CraftingTab::Utility => imgs.icon_utility,
CraftingTab::Weapon => imgs.icon_weapon,
CraftingTab::Bag => imgs.icon_bag,
}
}
fn satisfies(&self, item: &ItemDef) -> bool {
match self {
CraftingTab::All => true,
CraftingTab::Food => item.tags().contains(&ItemTag::Food),
CraftingTab::Armor => match item.kind() {
ItemKind::Armor(_) => !item.tags().contains(&ItemTag::Bag),
_ => false,
},
CraftingTab::Glider => matches!(item.kind(), ItemKind::Glider(_)),
CraftingTab::Potion => item.tags().contains(&ItemTag::Potion),
CraftingTab::Bag => item.tags().contains(&ItemTag::Bag),
CraftingTab::Tool => item.tags().contains(&ItemTag::CraftingTool),
CraftingTab::Utility => item.tags().contains(&ItemTag::Utility),
CraftingTab::Weapon => match item.kind() {
ItemKind::Tool(_) => !item.tags().contains(&ItemTag::CraftingTool),
_ => false,
},
CraftingTab::Dismantle => match item.kind() {
ItemKind::Ingredient { .. } => !item.tags().contains(&ItemTag::CraftingTool),
_ => false,
},
}
}
}
pub struct State { pub struct State {
ids: Ids, ids: Ids,
@ -155,15 +219,6 @@ impl<'a> Widget for Crafting<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { state, ui, .. } = args; let widget::UpdateArgs { state, ui, .. } = args;
if state.ids.recipe_names.len() < self.client.recipe_book().iter().len() {
state.update(|state| {
state.ids.recipe_names.resize(
self.client.recipe_book().iter().len(),
&mut ui.widget_id_generator(),
)
});
}
let mut events = Vec::new(); let mut events = Vec::new();
// Tooltips // Tooltips
@ -211,20 +266,35 @@ impl<'a> Widget for Crafting<'a> {
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.desc_text_color(TEXT_COLOR); .desc_text_color(TEXT_COLOR);
// Frame and window
Image::new(self.imgs.crafting_window) Image::new(self.imgs.crafting_window)
.bottom_right_with_margins_on(ui.window, 308.0, 450.0) .bottom_right_with_margins_on(ui.window, 308.0, 450.0)
.color(Some(UI_MAIN)) .color(Some(UI_MAIN))
.w_h(422.0, 460.0) .w_h(422.0, 460.0)
.set(state.ids.window, ui); .set(state.ids.window, ui);
// Search Background
// I couldn't find a way to manually set they layer of a widget
// If it is possible, please move this code (for rectangle) down to the code for
// search input
if self.show.crafting_search_key.is_some() {
Rectangle::fill([114.0, 20.0])
.top_left_with_margins_on(state.ids.window, 52.0, 26.0)
.hsla(0.0, 0.0, 0.0, 0.7)
.set(state.ids.input_bg_search, ui);
}
// Window
Image::new(self.imgs.crafting_frame) Image::new(self.imgs.crafting_frame)
.middle_of(state.ids.window) .middle_of(state.ids.window)
.color(Some(UI_HIGHLIGHT_0)) .color(Some(UI_HIGHLIGHT_0))
.w_h(422.0, 460.0) .w_h(422.0, 460.0)
.set(state.ids.window_frame, ui); .set(state.ids.window_frame, ui);
// Crafting Icon
Image::new(self.imgs.crafting_icon_bordered) Image::new(self.imgs.crafting_icon_bordered)
.w_h(38.0, 38.0) .w_h(38.0, 38.0)
.top_left_with_margins_on(state.ids.window_frame, 4.0, 4.0) .top_left_with_margins_on(state.ids.window_frame, 4.0, 4.0)
.set(state.ids.icon, ui); .set(state.ids.icon, ui);
// Close Button // Close Button
if Button::image(self.imgs.close_button) if Button::image(self.imgs.close_button)
.w_h(24.0, 25.0) .w_h(24.0, 25.0)
@ -254,105 +324,83 @@ impl<'a> Widget for Crafting<'a> {
.top_right_with_margins_on(state.ids.window, 74.0, 5.0) .top_right_with_margins_on(state.ids.window, 74.0, 5.0)
.scroll_kids_vertically() .scroll_kids_vertically()
.set(state.ids.align_ing, ui); .set(state.ids.align_ing, ui);
// Category Tabs // Category Tabs
if state.ids.category_bgs.len() < SelectedCraftingTab::iter().enumerate().len() { if state.ids.category_bgs.len() < CraftingTab::iter().enumerate().len() {
state.update(|s| { state.update(|s| {
s.ids.category_bgs.resize( s.ids.category_bgs.resize(
SelectedCraftingTab::iter().enumerate().len(), CraftingTab::iter().enumerate().len(),
&mut ui.widget_id_generator(), &mut ui.widget_id_generator(),
) )
}) })
}; };
if state.ids.category_tabs.len() < SelectedCraftingTab::iter().enumerate().len() { if state.ids.category_tabs.len() < CraftingTab::iter().enumerate().len() {
state.update(|s| { state.update(|s| {
s.ids.category_tabs.resize( s.ids.category_tabs.resize(
SelectedCraftingTab::iter().enumerate().len(), CraftingTab::iter().enumerate().len(),
&mut ui.widget_id_generator(), &mut ui.widget_id_generator(),
) )
}) })
}; };
if state.ids.category_imgs.len() < SelectedCraftingTab::iter().enumerate().len() { if state.ids.category_imgs.len() < CraftingTab::iter().enumerate().len() {
state.update(|s| { state.update(|s| {
s.ids.category_imgs.resize( s.ids.category_imgs.resize(
SelectedCraftingTab::iter().enumerate().len(), CraftingTab::iter().enumerate().len(),
&mut ui.widget_id_generator(), &mut ui.widget_id_generator(),
) )
}) })
}; };
let sel_crafting_tab = &self.show.crafting_tab; let sel_crafting_tab = &self.show.crafting_tab;
for i in SelectedCraftingTab::iter().enumerate() { for (i, crafting_tab) in CraftingTab::iter().enumerate() {
// TODO: i18n! let tab_img = crafting_tab.img_id(self.imgs);
let tab_name = match i.1 {
SelectedCraftingTab::Armor => "Armor",
SelectedCraftingTab::Dismantle => "Dismantle",
SelectedCraftingTab::Food => "Food",
SelectedCraftingTab::Glider => "Gliders",
SelectedCraftingTab::Potion => "Potions",
SelectedCraftingTab::Tool => "Tools",
SelectedCraftingTab::Utility => "Utility",
SelectedCraftingTab::Weapon => "Weapons",
SelectedCraftingTab::Bag => "Bags",
};
let tab_img = match i.1 {
SelectedCraftingTab::Armor => self.imgs.icon_armor,
SelectedCraftingTab::Dismantle => self.imgs.icon_dismantle,
SelectedCraftingTab::Food => self.imgs.icon_food,
SelectedCraftingTab::Glider => self.imgs.icon_glider,
SelectedCraftingTab::Potion => self.imgs.icon_potion,
SelectedCraftingTab::Tool => self.imgs.icon_tools,
SelectedCraftingTab::Utility => self.imgs.icon_utility,
SelectedCraftingTab::Weapon => self.imgs.icon_weapon,
SelectedCraftingTab::Bag => self.imgs.icon_bag,
};
// Button Background // Button Background
let mut bg = Image::new(self.imgs.pixel) let mut bg = Image::new(self.imgs.pixel)
.w_h(40.0, 30.0) .w_h(40.0, 30.0)
.color(Some(UI_MAIN)); .color(Some(UI_MAIN));
if i.0 == 0 { if i == 0 {
bg = bg.top_left_with_margins_on(state.ids.window_frame, 50.0, -40.0) bg = bg.top_left_with_margins_on(state.ids.window_frame, 50.0, -40.0)
} else { } else {
bg = bg.down_from(state.ids.category_bgs[i.0 - 1], 0.0) bg = bg.down_from(state.ids.category_bgs[i - 1], 0.0)
}; };
bg.set(state.ids.category_bgs[i.0], ui); bg.set(state.ids.category_bgs[i], ui);
// Category Button // Category Button
if Button::image(if i.1 == *sel_crafting_tab { if Button::image(if crafting_tab == *sel_crafting_tab {
self.imgs.wpn_icon_border_pressed self.imgs.wpn_icon_border_pressed
} else { } else {
self.imgs.wpn_icon_border self.imgs.wpn_icon_border
}) })
.wh_of(state.ids.category_bgs[i.0]) .wh_of(state.ids.category_bgs[i])
.middle_of(state.ids.category_bgs[i.0]) .middle_of(state.ids.category_bgs[i])
.hover_image(if i.1 == *sel_crafting_tab { .hover_image(if crafting_tab == *sel_crafting_tab {
self.imgs.wpn_icon_border_pressed self.imgs.wpn_icon_border_pressed
} else { } else {
self.imgs.wpn_icon_border_mo self.imgs.wpn_icon_border_mo
}) })
.press_image(if i.1 == *sel_crafting_tab { .press_image(if crafting_tab == *sel_crafting_tab {
self.imgs.wpn_icon_border_pressed self.imgs.wpn_icon_border_pressed
} else { } else {
self.imgs.wpn_icon_border_press self.imgs.wpn_icon_border_press
}) })
.with_tooltip( .with_tooltip(
self.tooltip_manager, self.tooltip_manager,
tab_name, &self.localized_strings.get(crafting_tab.name_key()),
"", "",
&tabs_tooltip, &tabs_tooltip,
TEXT_COLOR, TEXT_COLOR,
) )
.set(state.ids.category_tabs[i.0], ui) .set(state.ids.category_tabs[i], ui)
.was_clicked() .was_clicked()
{ {
events.push(Event::ChangeCraftingTab(i.1)) events.push(Event::ChangeCraftingTab(crafting_tab))
}; };
// Tab images // Tab images
Image::new(tab_img) Image::new(tab_img)
.middle_of(state.ids.category_tabs[i.0]) .middle_of(state.ids.category_tabs[i])
.w_h(20.0, 20.0) .w_h(20.0, 20.0)
.graphics_for(state.ids.category_tabs[i.0]) .graphics_for(state.ids.category_tabs[i])
.set(state.ids.category_imgs[i.0], ui); .set(state.ids.category_imgs[i], ui);
} }
let client = &self.client;
// First available recipes, then unavailable ones, each alphabetically // First available recipes, then unavailable ones, each alphabetically
// In the triples, "name" is the recipe book key, and "recipe.output.0.name()" // In the triples, "name" is the recipe book key, and "recipe.output.0.name()"
// is the display name (as stored in the item descriptors) // is the display name (as stored in the item descriptors)
@ -366,6 +414,17 @@ impl<'a> Widget for Crafting<'a> {
.client .client
.recipe_book() .recipe_book()
.iter() .iter()
.filter(|(_, recipe)| {
let output_name = recipe.output.0.name.to_lowercase();
if let Some(key) = &self.show.crafting_search_key {
key.as_str()
.to_lowercase()
.split_whitespace()
.all(|substring| output_name.contains(substring))
} else {
true
}
})
.map(|(name, recipe)| { .map(|(name, recipe)| {
let at_least_some_ingredients = recipe.inputs.iter().any(|(input, amount)| { let at_least_some_ingredients = recipe.inputs.iter().any(|(input, amount)| {
*amount > 0 *amount > 0
@ -375,7 +434,7 @@ impl<'a> Widget for Crafting<'a> {
.unwrap_or(false) .unwrap_or(false)
}) })
}); });
let state = if client.available_recipes().contains(name.as_str()) { let state = if self.client.available_recipes().contains(name.as_str()) {
RecipeIngredientQuantity::All RecipeIngredientQuantity::All
} else if at_least_some_ingredients { } else if at_least_some_ingredients {
RecipeIngredientQuantity::Some RecipeIngredientQuantity::Some
@ -386,129 +445,19 @@ impl<'a> Widget for Crafting<'a> {
}) })
.collect(); .collect();
ordered_recipes.sort_by_key(|(_, recipe, state)| (*state, recipe.output.0.name())); ordered_recipes.sort_by_key(|(_, recipe, state)| (*state, recipe.output.0.name()));
match &state.selected_recipe {
None => {},
Some(recipe) => {
let can_perform = client.available_recipes().contains(recipe.as_str());
// Ingredients Text
Text::new(&self.localized_strings.get("hud.crafting.ingredients"))
.top_left_with_margins_on(state.ids.align_ing, 10.0, 5.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(18))
.color(TEXT_COLOR)
.set(state.ids.ingredients_txt, ui);
// Craft button
if Button::image(self.imgs.button)
.w_h(105.0, 25.0)
.hover_image(
can_perform
.then_some(self.imgs.button_hover)
.unwrap_or(self.imgs.button),
)
.press_image(
can_perform
.then_some(self.imgs.button_press)
.unwrap_or(self.imgs.button),
)
.label(&self.localized_strings.get("hud.crafting.craft"))
.label_y(conrod_core::position::Relative::Scalar(1.0))
.label_color(can_perform.then_some(TEXT_COLOR).unwrap_or(TEXT_GRAY_COLOR))
.label_font_size(self.fonts.cyri.scale(12))
.label_font_id(self.fonts.cyri.conrod_id)
.image_color(can_perform.then_some(TEXT_COLOR).unwrap_or(TEXT_GRAY_COLOR))
.mid_bottom_with_margin_on(state.ids.align_ing, -31.0)
.parent(state.ids.window_frame)
.set(state.ids.btn_craft, ui)
.was_clicked()
{
events.push(Event::CraftRecipe(recipe.clone()));
}
// Result Image BG
let quality_col_img = if let Some(recipe) = state
.selected_recipe
.as_ref()
.and_then(|r| self.client.recipe_book().get(r.as_str()))
{
match recipe.output.0.quality {
Quality::Low => self.imgs.inv_slot_grey,
Quality::Common => self.imgs.inv_slot,
Quality::Moderate => self.imgs.inv_slot_green,
Quality::High => self.imgs.inv_slot_blue,
Quality::Epic => self.imgs.inv_slot_purple,
Quality::Legendary => self.imgs.inv_slot_gold,
Quality::Artifact => self.imgs.inv_slot_orange,
_ => self.imgs.inv_slot_red,
}
} else {
self.imgs.inv_slot
};
Image::new(quality_col_img)
.w_h(60.0, 60.0)
.top_right_with_margins_on(state.ids.align_ing, 15.0, 10.0)
.parent(state.ids.align_ing)
.set(state.ids.output_img_frame, ui);
if let Some(recipe) = state
.selected_recipe
.as_ref()
.and_then(|r| self.client.recipe_book().get(r.as_str()))
{
let output_text = format!("x{}", &recipe.output.1.to_string());
// Output Image
Button::image(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img((&*recipe.output.0).into()),
self.pulse,
))
.w_h(55.0, 55.0)
.label(&output_text)
.label_color(TEXT_COLOR)
.label_font_size(self.fonts.cyri.scale(14))
.label_font_id(self.fonts.cyri.conrod_id)
.label_y(conrod_core::position::Relative::Scalar(-24.0))
.label_x(conrod_core::position::Relative::Scalar(24.0))
.middle_of(state.ids.output_img_frame)
.with_item_tooltip(
self.item_tooltip_manager,
&*recipe.output.0,
&None,
&item_tooltip,
)
.set(state.ids.output_img, ui);
}
},
}
// Recipe list // Recipe list
if state.ids.recipe_names.len() < self.client.recipe_book().iter().len() {
state.update(|state| {
state.ids.recipe_names.resize(
self.client.recipe_book().iter().len(),
&mut ui.widget_id_generator(),
)
});
}
for (i, (name, recipe, quantity)) in ordered_recipes for (i, (name, recipe, quantity)) in ordered_recipes
.into_iter() .into_iter()
.filter(|(_name, recipe, _quantity)| match &self.show.crafting_tab { .filter(|(_, recipe, _)| self.show.crafting_tab.satisfies(recipe.output.0.as_ref()))
SelectedCraftingTab::Food => recipe.output.0.tags().contains(&ItemTag::Food),
SelectedCraftingTab::Armor => match recipe.output.0.kind() {
ItemKind::Armor(_) => !recipe.output.0.tags().contains(&ItemTag::Bag),
_ => false,
},
SelectedCraftingTab::Glider => {
matches!(recipe.output.0.kind(), ItemKind::Glider(_))
},
SelectedCraftingTab::Potion => recipe.output.0.tags().contains(&ItemTag::Potion),
SelectedCraftingTab::Bag => recipe.output.0.tags().contains(&ItemTag::Bag),
SelectedCraftingTab::Tool => {
recipe.output.0.tags().contains(&ItemTag::CraftingTool)
},
SelectedCraftingTab::Utility => recipe.output.0.tags().contains(&ItemTag::Utility),
SelectedCraftingTab::Weapon => match recipe.output.0.kind() {
ItemKind::Tool(_) => !recipe.output.0.tags().contains(&ItemTag::CraftingTool),
_ => false,
},
SelectedCraftingTab::Dismantle => match recipe.output.0.kind() {
ItemKind::Ingredient { .. } => {
!recipe.output.0.tags().contains(&ItemTag::CraftingTool)
},
_ => false,
},
})
.enumerate() .enumerate()
{ {
let button = Button::image( let button = Button::image(
@ -562,11 +511,11 @@ impl<'a> Widget for Crafting<'a> {
} }
} }
//Ingredients // Selected Recipe
if let Some(recipe) = state if let Some((recipe_name, recipe)) = state
.selected_recipe .selected_recipe
.as_ref() .as_ref()
.and_then(|r| self.client.recipe_book().get(r.as_str())) .and_then(|rn| self.client.recipe_book().get(rn.as_str()).map(|r| (rn, r)))
{ {
// Title // Title
Text::new(&recipe.output.0.name()) Text::new(&recipe.output.0.name())
@ -576,6 +525,132 @@ impl<'a> Widget for Crafting<'a> {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.parent(state.ids.window) .parent(state.ids.window)
.set(state.ids.title_ing, ui); .set(state.ids.title_ing, ui);
let can_perform = self
.client
.available_recipes()
.contains(recipe_name.as_str());
// Craft button
if Button::image(self.imgs.button)
.w_h(105.0, 25.0)
.hover_image(
can_perform
.then_some(self.imgs.button_hover)
.unwrap_or(self.imgs.button),
)
.press_image(
can_perform
.then_some(self.imgs.button_press)
.unwrap_or(self.imgs.button),
)
.label(&self.localized_strings.get("hud.crafting.craft"))
.label_y(conrod_core::position::Relative::Scalar(1.0))
.label_color(can_perform.then_some(TEXT_COLOR).unwrap_or(TEXT_GRAY_COLOR))
.label_font_size(self.fonts.cyri.scale(12))
.label_font_id(self.fonts.cyri.conrod_id)
.image_color(can_perform.then_some(TEXT_COLOR).unwrap_or(TEXT_GRAY_COLOR))
.mid_bottom_with_margin_on(state.ids.align_ing, -31.0)
.parent(state.ids.window_frame)
.set(state.ids.btn_craft, ui)
.was_clicked()
{
events.push(Event::CraftRecipe(recipe_name.clone()));
}
// Output Image Frame
let quality_col_img = match recipe.output.0.quality {
Quality::Low => self.imgs.inv_slot_grey,
Quality::Common => self.imgs.inv_slot,
Quality::Moderate => self.imgs.inv_slot_green,
Quality::High => self.imgs.inv_slot_blue,
Quality::Epic => self.imgs.inv_slot_purple,
Quality::Legendary => self.imgs.inv_slot_gold,
Quality::Artifact => self.imgs.inv_slot_orange,
_ => self.imgs.inv_slot_red,
};
Image::new(quality_col_img)
.w_h(60.0, 60.0)
.top_right_with_margins_on(state.ids.align_ing, 15.0, 10.0)
.parent(state.ids.align_ing)
.set(state.ids.output_img_frame, ui);
let output_text = format!("x{}", &recipe.output.1.to_string());
// Output Image
Button::image(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img((&*recipe.output.0).into()),
self.pulse,
))
.w_h(55.0, 55.0)
.label(&output_text)
.label_color(TEXT_COLOR)
.label_font_size(self.fonts.cyri.scale(14))
.label_font_id(self.fonts.cyri.conrod_id)
.label_y(conrod_core::position::Relative::Scalar(-24.0))
.label_x(conrod_core::position::Relative::Scalar(24.0))
.middle_of(state.ids.output_img_frame)
.with_item_tooltip(
self.item_tooltip_manager,
&*recipe.output.0,
&None,
&item_tooltip,
)
.set(state.ids.output_img, ui);
// Tags
if state.ids.tags_ing.len() < CraftingTab::iter().len() {
state.update(|state| {
state
.ids
.tags_ing
.resize(CraftingTab::iter().len(), &mut ui.widget_id_generator())
});
}
for (row, chunk) in CraftingTab::iter()
.filter(|crafting_tab| match crafting_tab {
CraftingTab::All => false,
_ => crafting_tab.satisfies(recipe.output.0.as_ref()),
})
.filter(|crafting_tab| crafting_tab != &self.show.crafting_tab)
.collect::<Vec<_>>()
.chunks(3)
.enumerate()
{
for (col, crafting_tab) in chunk.iter().rev().enumerate() {
let i = 3 * row + col;
let icon = Image::new(crafting_tab.img_id(self.imgs))
.w_h(20.0, 20.0)
.parent(state.ids.window);
let icon = if col == 0 {
icon.bottom_right_with_margins_on(
state.ids.output_img_frame,
-24.0 - 24.0 * (row as f64),
4.0,
)
} else {
icon.left_from(state.ids.tags_ing[i - 1], 4.0)
};
icon.with_tooltip(
self.tooltip_manager,
&self.localized_strings.get(crafting_tab.name_key()),
"",
&tabs_tooltip,
TEXT_COLOR,
)
.set(state.ids.tags_ing[i], ui);
}
}
// Ingredients Text
Text::new(&self.localized_strings.get("hud.crafting.ingredients"))
.top_left_with_margins_on(state.ids.align_ing, 10.0, 5.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(18))
.color(TEXT_COLOR)
.set(state.ids.ingredients_txt, ui);
// Ingredient images with tooltip // Ingredient images with tooltip
if state.ids.ingredient_frame.len() < recipe.inputs().len() { if state.ids.ingredient_frame.len() < recipe.inputs().len() {
state.update(|state| { state.update(|state| {
@ -725,6 +800,56 @@ impl<'a> Widget for Crafting<'a> {
} }
} }
} }
// Search / Title Recipes
if let Some(key) = &self.show.crafting_search_key {
if Button::image(self.imgs.close_btn)
.top_left_with_margins_on(state.ids.align_rec, -20.0, 5.0)
.w_h(14.0, 14.0)
.hover_image(self.imgs.close_btn_hover)
.press_image(self.imgs.close_btn_press)
.parent(state.ids.window)
.set(state.ids.btn_close_search, ui)
.was_clicked()
{
events.push(Event::SearchRecipe(None));
}
if let Some(string) = TextEdit::new(key.as_str())
.top_left_with_margins_on(state.ids.btn_close_search, -2.0, 18.0)
.w_h(90.0, 20.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR)
.parent(state.ids.window)
.set(state.ids.input_search, ui)
{
events.push(Event::SearchRecipe(Some(string)));
}
} else {
Text::new(&self.localized_strings.get("hud.crafting.recipes"))
.mid_top_with_margin_on(state.ids.align_rec, -22.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR)
.parent(state.ids.window)
.set(state.ids.title_rec, ui);
Rectangle::fill_with([114.0, 20.0], color::TRANSPARENT)
.top_left_with_margins_on(state.ids.window, 52.0, 26.0)
.graphics_for(state.ids.btn_open_search)
.set(state.ids.input_overlay_search, ui);
if Button::image(self.imgs.search_btn)
.top_left_with_margins_on(state.ids.align_rec, -21.0, 5.0)
.w_h(16.0, 16.0)
.hover_image(self.imgs.search_btn_hover)
.press_image(self.imgs.search_btn_press)
.parent(state.ids.window)
.set(state.ids.btn_open_search, ui)
.was_clicked()
{
events.push(Event::SearchRecipe(Some(String::new())));
events.push(Event::Focus(state.ids.input_search));
}
}
// Scrollbars // Scrollbars
Scrollbar::y_axis(state.ids.align_rec) Scrollbar::y_axis(state.ids.align_rec)
.thickness(5.0) .thickness(5.0)
@ -735,15 +860,6 @@ impl<'a> Widget for Crafting<'a> {
.rgba(0.33, 0.33, 0.33, 1.0) .rgba(0.33, 0.33, 0.33, 1.0)
.set(state.ids.scrollbar_ing, ui); .set(state.ids.scrollbar_ing, ui);
// Title Recipes and Ingredients
Text::new(&self.localized_strings.get("hud.crafting.recipes"))
.mid_top_with_margin_on(state.ids.align_rec, -22.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR)
.parent(state.ids.window)
.set(state.ids.title_rec, ui);
events events
} }
} }

View File

@ -88,15 +88,6 @@ image_ids! {
// Social Window // Social Window
social_frame_on: "voxygen.element.misc_bg.social_frame", social_frame_on: "voxygen.element.misc_bg.social_frame",
social_bg_on: "voxygen.element.misc_bg.social_bg", 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_online: "voxygen.element.misc_bg.social_tab_online",
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
crafting_window: "voxygen.element.misc_bg.crafting", crafting_window: "voxygen.element.misc_bg.crafting",
@ -110,6 +101,7 @@ image_ids! {
icon_dismantle: "voxygen.element.icons.dismantle", icon_dismantle: "voxygen.element.icons.dismantle",
icon_food: "voxygen.element.icons.foods", icon_food: "voxygen.element.icons.foods",
icon_glider: "voxygen.element.icons.gliders", icon_glider: "voxygen.element.icons.gliders",
icon_globe: "voxygen.element.icons.globe",
icon_potion: "voxygen.element.icons.potions", icon_potion: "voxygen.element.icons.potions",
icon_utility: "voxygen.element.icons.utilities", icon_utility: "voxygen.element.icons.utilities",
icon_weapon: "voxygen.element.icons.weapons", icon_weapon: "voxygen.element.icons.weapons",
@ -403,6 +395,10 @@ image_ids! {
close_button_hover: "voxygen.element.buttons.close_btn_hover", close_button_hover: "voxygen.element.buttons.close_btn_hover",
close_button_press: "voxygen.element.buttons.close_btn_press", close_button_press: "voxygen.element.buttons.close_btn_press",
// Search-button
search_btn: "voxygen.element.buttons.search_btn",
search_btn_hover: "voxygen.element.buttons.search_btn_hover",
search_btn_press: "voxygen.element.buttons.search_btn_press",
// Inventory // Inventory
collapse_btn: "voxygen.element.buttons.inv_collapse", collapse_btn: "voxygen.element.buttons.inv_collapse",
collapse_btn_hover: "voxygen.element.buttons.inv_collapse_hover", collapse_btn_hover: "voxygen.element.buttons.inv_collapse_hover",

View File

@ -31,7 +31,7 @@ use buffs::BuffsBar;
use buttons::Buttons; use buttons::Buttons;
use chat::Chat; use chat::Chat;
use chrono::NaiveTime; use chrono::NaiveTime;
use crafting::{Crafting, SelectedCraftingTab}; use crafting::{Crafting, CraftingTab};
use diary::{Diary, SelectedSkillTree}; use diary::{Diary, SelectedSkillTree};
use esc_menu::EscMenu; use esc_menu::EscMenu;
use group::Group; use group::Group;
@ -44,7 +44,7 @@ use prompt_dialog::PromptDialog;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings_window::{SettingsTab, SettingsWindow}; use settings_window::{SettingsTab, SettingsWindow};
use skillbar::Skillbar; use skillbar::Skillbar;
use social::{Social, SocialTab}; use social::Social;
use trade::Trade; use trade::Trade;
use crate::{ use crate::{
@ -546,8 +546,9 @@ pub struct Show {
ingame: bool, ingame: bool,
settings_tab: SettingsTab, settings_tab: SettingsTab,
skilltreetab: SelectedSkillTree, skilltreetab: SelectedSkillTree,
crafting_tab: SelectedCraftingTab, crafting_tab: CraftingTab,
social_tab: SocialTab, crafting_search_key: Option<String>,
social_search_key: Option<String>,
want_grab: bool, want_grab: bool,
stats: bool, stats: bool,
free_look: bool, free_look: bool,
@ -561,6 +562,10 @@ impl Show {
self.bag = open; self.bag = open;
self.map = false; self.map = false;
self.want_grab = !open; self.want_grab = !open;
if !open {
self.crafting = false;
}
} }
} }
@ -590,6 +595,10 @@ impl Show {
fn social(&mut self, open: bool) { fn social(&mut self, open: bool) {
if !self.esc_menu { if !self.esc_menu {
if !self.social && open {
// rising edge detector
self.search_social_players(None);
}
self.social = open; self.social = open;
self.diary = false; self.diary = false;
self.want_grab = !open; self.want_grab = !open;
@ -598,6 +607,10 @@ impl Show {
fn crafting(&mut self, open: bool) { fn crafting(&mut self, open: bool) {
if !self.esc_menu { if !self.esc_menu {
if !self.crafting && open {
// rising edge detector
self.search_crafting_recipe(None);
}
self.crafting = open; self.crafting = open;
self.bag = open; self.bag = open;
self.map = false; self.map = false;
@ -711,11 +724,6 @@ impl Show {
fn toggle_crafting(&mut self) { self.crafting(!self.crafting) } fn toggle_crafting(&mut self) { self.crafting(!self.crafting) }
fn open_social_tab(&mut self, social_tab: SocialTab) {
self.social_tab = social_tab;
self.diary = false;
}
fn toggle_spell(&mut self) { fn toggle_spell(&mut self) {
self.diary = !self.diary; self.diary = !self.diary;
self.bag = false; self.bag = false;
@ -730,8 +738,14 @@ impl Show {
self.social = false; self.social = false;
} }
fn selected_crafting_tab(&mut self, sel_cat: SelectedCraftingTab) { fn selected_crafting_tab(&mut self, sel_cat: CraftingTab) { self.crafting_tab = sel_cat; }
self.crafting_tab = sel_cat;
fn search_crafting_recipe(&mut self, search_key: Option<String>) {
self.crafting_search_key = search_key;
}
fn search_social_players(&mut self, search_key: Option<String>) {
self.social_search_key = search_key;
} }
/// If all of the menus are closed, adjusts coordinates of cursor to center /// If all of the menus are closed, adjusts coordinates of cursor to center
@ -890,8 +904,9 @@ impl Hud {
group_menu: false, group_menu: false,
settings_tab: SettingsTab::Interface, settings_tab: SettingsTab::Interface,
skilltreetab: SelectedSkillTree::General, skilltreetab: SelectedSkillTree::General,
crafting_tab: SelectedCraftingTab::Armor, crafting_tab: CraftingTab::All,
social_tab: SocialTab::Online, crafting_search_key: None,
social_search_key: None,
want_grab: true, want_grab: true,
ingame: true, ingame: true,
stats: false, stats: false,
@ -2368,7 +2383,6 @@ impl Hud {
Some(bag::Event::Close) => { Some(bag::Event::Close) => {
self.show.stats = false; self.show.stats = false;
self.show.bag(false); self.show.bag(false);
self.show.crafting(false);
if !self.show.social { if !self.show.social {
self.show.want_grab = true; self.show.want_grab = true;
self.force_ungrab = false; self.force_ungrab = false;
@ -2469,7 +2483,6 @@ impl Hud {
crafting::Event::Close => { crafting::Event::Close => {
self.show.stats = false; self.show.stats = false;
self.show.crafting(false); self.show.crafting(false);
self.show.bag(false);
if !self.show.social { if !self.show.social {
self.show.want_grab = true; self.show.want_grab = true;
self.force_ungrab = false; self.force_ungrab = false;
@ -2480,6 +2493,12 @@ impl Hud {
crafting::Event::ChangeCraftingTab(sel_cat) => { crafting::Event::ChangeCraftingTab(sel_cat) => {
self.show.selected_crafting_tab(sel_cat); self.show.selected_crafting_tab(sel_cat);
}, },
crafting::Event::Focus(widget_id) => {
self.to_focus = Some(Some(widget_id));
},
crafting::Event::SearchRecipe(search_key) => {
self.show.search_crafting_recipe(search_key);
},
} }
} }
} }
@ -2735,10 +2754,13 @@ impl Hud {
self.force_ungrab = true self.force_ungrab = true
}; };
}, },
social::Event::ChangeSocialTab(social_tab) => { social::Event::Focus(widget_id) => {
self.show.open_social_tab(social_tab) self.to_focus = Some(Some(widget_id));
}, },
social::Event::Invite(uid) => events.push(Event::InviteMember(uid)), social::Event::Invite(uid) => events.push(Event::InviteMember(uid)),
social::Event::SearchPlayers(search_key) => {
self.show.search_social_players(search_key)
},
} }
} }
} }

View File

@ -11,7 +11,7 @@ use client::{self, Client};
use common::{comp::group, uid::Uid}; use common::{comp::group, uid::Uid};
use conrod_core::{ use conrod_core::{
color, color,
widget::{self, Button, Image, Rectangle, Scrollbar, Text}, widget::{self, Button, Image, Rectangle, Scrollbar, Text, TextEdit},
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
}; };
use itertools::Itertools; use itertools::Itertools;
@ -27,25 +27,14 @@ widget_ids! {
icon, icon,
scrollbar, scrollbar,
online_align, online_align,
online_tab,
names_align,
name_txt,
player_levels[],
player_names[], player_names[],
player_zones[],
online_txt, online_txt,
online_no, online_no,
levels_align,
level_txt,
zones_align,
zone_txt,
friends_tab,
//friends_tab_icon,
faction_tab,
//faction_tab_icon,
friends_test,
faction_test,
invite_button, invite_button,
player_search_icon,
player_search_input,
player_search_input_bg,
player_search_input_overlay,
} }
} }
@ -56,12 +45,6 @@ pub struct State {
selected_uid: Option<(Uid, Instant)>, selected_uid: Option<(Uid, Instant)>,
} }
pub enum SocialTab {
Online,
Friends,
Faction,
}
#[derive(WidgetCommon)] #[derive(WidgetCommon)]
pub struct Social<'a> { pub struct Social<'a> {
show: &'a Show, show: &'a Show,
@ -106,7 +89,8 @@ impl<'a> Social<'a> {
pub enum Event { pub enum Event {
Close, Close,
Invite(Uid), Invite(Uid),
ChangeSocialTab(SocialTab), Focus(widget::Id),
SearchPlayers(Option<String>),
} }
impl<'a> Widget for Social<'a> { impl<'a> Widget for Social<'a> {
@ -145,33 +129,27 @@ impl<'a> Widget for Social<'a> {
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.desc_text_color(TEXT_COLOR); .desc_text_color(TEXT_COLOR);
// Window frame and BG // Window BG
let pos = if self.show.group || self.show.group_menu { Image::new(self.imgs.social_bg_on)
200.0 .bottom_left_with_margins_on(ui.window, 308.0, 25.0)
} else {
25.0
};
// 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)
.bottom_left_with_margins_on(ui.window, 308.0, pos)
.color(Some(UI_MAIN)) .color(Some(UI_MAIN))
.w_h(280.0, 460.0) .w_h(280.0, 460.0)
.set(state.ids.bg, ui); .set(state.ids.bg, ui);
Image::new(window_frame) // Search Background
// I couldn't find a way to manually set they layer of a widget
// If it is possible, please move this code (for rectangle) down to the code for
// search input
Rectangle::fill([248.0, 20.0])
.top_left_with_margins_on(state.ids.bg, 52.0, 27.0)
.hsla(0.0, 0.0, 0.0, 0.7)
.set(state.ids.player_search_input_bg, ui);
// Window frame
Image::new(self.imgs.social_frame_on)
.middle_of(state.ids.bg) .middle_of(state.ids.bg)
.color(Some(UI_HIGHLIGHT_0)) .color(Some(UI_HIGHLIGHT_0))
.w_h(280.0, 460.0) .w_h(280.0, 460.0)
.set(state.ids.frame, ui); .set(state.ids.frame, ui);
// Icon // Icon
Image::new(self.imgs.social) Image::new(self.imgs.social)
.w_h(30.0, 30.0) .w_h(30.0, 30.0)
@ -200,147 +178,23 @@ impl<'a> Widget for Social<'a> {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.title, ui); .set(state.ids.title, ui);
// Tabs Buttons
// Online Tab Button
if Button::image(match &self.show.social_tab {
SocialTab::Online => self.imgs.social_tab_online,
_ => self.imgs.social_tab_inact,
})
.w_h(30.0, 44.0)
.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, -27.0)
.set(state.ids.online_tab, ui)
.was_clicked()
{
events.push(Event::ChangeSocialTab(SocialTab::Online));
}
// 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 {
let players = self let players = self
.client .client
.player_list() .player_list()
.iter() .iter()
.filter(|(_, p)| p.is_online); .filter(|(_, p)| p.is_online);
let count = players.clone().count(); let player_count = players.clone().count();
let height = if count > 1 {
count as f64 - 1.0 + 20.0 * count as f64 - 1.0 // Content Alignment
} else {
1.0
};
// Content Alignments
Rectangle::fill_with([270.0, 346.0], color::TRANSPARENT) Rectangle::fill_with([270.0, 346.0], color::TRANSPARENT)
.mid_top_with_margin_on(state.ids.frame, 74.0) .mid_top_with_margin_on(state.ids.frame, 74.0)
.scroll_kids_vertically() .scroll_kids_vertically()
.set(state.ids.online_align, ui); .set(state.ids.online_align, ui);
Rectangle::fill_with([133.0, height], 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, height], color::TRANSPARENT)
.right_from(state.ids.names_align, 2.0)
.crop_kids()
.set(state.ids.levels_align, ui);
Rectangle::fill_with([94.0, height], 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) Scrollbar::y_axis(state.ids.online_align)
.thickness(4.0) .thickness(4.0)
.color(Color::Rgba(0.79, 1.09, 1.09, 0.0)) .color(Color::Rgba(0.79, 1.09, 1.09, 0.0))
.set(state.ids.scrollbar, ui); .set(state.ids.scrollbar, ui);
//
// Headlines
//
if Button::image(self.imgs.nothing)
.w_h(133.0, 18.0)
.mid_top_with_margin_on(state.ids.frame, 52.0)
.label(&self.localized_strings.get(""))
.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("")
.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("") // TODO: Enable zone here later
.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 // Online Text
Text::new(&self.localized_strings.get("hud.social.online")) Text::new(&self.localized_strings.get("hud.social.online"))
.bottom_left_with_margins_on(state.ids.frame, 18.0, 10.0) .bottom_left_with_margins_on(state.ids.frame, 18.0, 10.0)
@ -348,56 +202,60 @@ impl<'a> Widget for Social<'a> {
.font_size(self.fonts.cyri.scale(14)) .font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.online_txt, ui); .set(state.ids.online_txt, ui);
Text::new(&count.to_string()) Text::new(&player_count.to_string())
.right_from(state.ids.online_txt, 5.0) .right_from(state.ids.online_txt, 5.0)
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14)) .font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.online_no, ui); .set(state.ids.online_no, ui);
// Adjust widget_id struct vec length to player count // Adjust widget_id struct vec length to player count
if state.ids.player_levels.len() < count { if state.ids.player_names.len() < player_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| { state.update(|s| {
s.ids s.ids
.player_names .player_names
.resize(count, &mut ui.widget_id_generator()) .resize(player_count, &mut ui.widget_id_generator())
}) })
}; };
if state.ids.player_zones.len() < count {
state.update(|s| { // Filter out yourself from the online list and perform search
s.ids
.player_zones
.resize(count, &mut ui.widget_id_generator())
})
};
// Create a name, level and zone row for every player in the list
// Filter out yourself from the online list
let my_uid = self.client.uid(); let my_uid = self.client.uid();
let mut player_list = players let mut player_list = players
.filter(|(uid, _)| Some(**uid) != my_uid) .filter(|(uid, _)| Some(**uid) != my_uid)
.filter(|(_, player)| {
self.show
.social_search_key
.as_ref()
.map(|search_key| {
search_key
.to_lowercase()
.split_whitespace()
.all(|substring| {
let player_alias = &player.player_alias.to_lowercase();
let character_name = player
.character
.as_ref()
.map(|character| character.name.to_lowercase());
player_alias.contains(substring)
|| character_name
.map(|cn| cn.contains(substring))
.unwrap_or(false)
})
})
.unwrap_or(true)
})
.collect_vec(); .collect_vec();
player_list.sort_by_key(|(_, player)| { player_list.sort_by_key(|(_, player)| {
player player
.character .character
.as_ref() .as_ref()
.map(|character| character.name.to_lowercase()) .map(|character| &character.name)
.unwrap_or_else(|| player.player_alias.to_string()) .unwrap_or(&player.player_alias)
.to_lowercase()
}); });
for (i, (&uid, player_info)) in player_list.into_iter().enumerate() { for (i, (&uid, player_info)) in player_list.into_iter().enumerate() {
let hide_username = true; let hide_username = true;
let zone = ""; // TODO Add real zone
let selected = state.selected_uid.map_or(false, |u| u.0 == uid); let selected = state.selected_uid.map_or(false, |u| u.0 == uid);
let alias = &player_info.player_alias; let alias = &player_info.player_alias;
let zone_name = match &player_info.character {
None => self.localized_strings.get("hud.group.in_menu").to_string(), /* character select or spectating */
_ => format!("{} ", &zone),
};
let name_text = match &player_info.character { let name_text = match &player_info.character {
Some(character) => { Some(character) => {
if hide_username { if hide_username {
@ -406,27 +264,23 @@ impl<'a> Widget for Social<'a> {
format!("[{}] {}", alias, &character.name) format!("[{}] {}", alias, &character.name)
} }
}, },
None => format!("{} [{}]", alias.clone(), zone_name), /* character select or None => format!(
* spectating */ "{} [{}]",
}; alias.clone(),
// Player name widgets self.localized_strings.get("hud.group.in_menu").to_string()
let button = Button::image(if !selected { ), // character select or spectating
self.imgs.nothing
} else {
self.imgs.selection
});
let button = if i == 0 {
button.mid_top_with_margin_on(state.ids.online_align, 1.0)
} else {
button.down_from(state.ids.player_names[i - 1], 1.0)
}; };
let acc_name_txt = format!( let acc_name_txt = format!(
"{}: {}", "{}: {}",
&self.localized_strings.get("hud.social.account"), &self.localized_strings.get("hud.social.account"),
alias alias
); );
button // Player name widget
.w_h(260.0, 20.0) let button = Button::image(if !selected {
self.imgs.nothing
} else {
self.imgs.selection
})
.hover_image(if selected { .hover_image(if selected {
self.imgs.selection self.imgs.selection
} else { } else {
@ -437,6 +291,13 @@ impl<'a> Widget for Social<'a> {
} else { } else {
self.imgs.selection_press self.imgs.selection_press
}) })
.w_h(260.0, 20.0);
let button = if i == 0 {
button.mid_top_with_margin_on(state.ids.online_align, 1.0)
} else {
button.down_from(state.ids.player_names[i - 1], 1.0)
};
if button
.label(&name_text) .label(&name_text)
.label_font_size(self.fonts.cyri.scale(14)) .label_font_size(self.fonts.cyri.scale(14))
.label_y(conrod_core::position::Relative::Scalar(1.0)) .label_y(conrod_core::position::Relative::Scalar(1.0))
@ -449,29 +310,8 @@ impl<'a> Widget for Social<'a> {
&button_tooltip, &button_tooltip,
TEXT_COLOR, TEXT_COLOR,
) )
.set(state.ids.player_names[i], ui); .set(state.ids.player_names[i], ui)
// Player Zones .was_clicked()
Button::image(if !selected {
self.imgs.nothing
} else {
self.imgs.selection
})
.w_h(94.0, 20.0)
.right_from(state.ids.player_levels[i], 2.0)
.label(&zone_name)
.label_font_size(self.fonts.cyri.scale(14))
.label_font_id(self.fonts.cyri.conrod_id)
.label_color(TEXT_COLOR)
.label_y(conrod_core::position::Relative::Scalar(1.0))
.parent(state.ids.zones_align)
.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()))); state.update(|s| s.selected_uid = Some((uid, Instant::now())));
} }
@ -500,12 +340,12 @@ impl<'a> Widget for Social<'a> {
.as_ref() .as_ref()
.map(|(s, _)| *s) .map(|(s, _)| *s)
.filter(|selected| { .filter(|selected| {
self.client.player_list().get(selected).map_or( self.client
false, .player_list()
|selected_player| { .get(selected)
.map_or(false, |selected_player| {
selected_player.is_online && selected_player.character.is_some() selected_player.is_online && selected_player.character.is_some()
}, })
)
}) })
.or_else(|| { .or_else(|| {
self.selected_entity self.selected_entity
@ -574,7 +414,33 @@ impl<'a> Widget for Social<'a> {
}); });
} }
} }
} // End of Online Tab
// Player Search
if Button::image(self.imgs.search_btn)
.top_left_with_margins_on(state.ids.frame, 54.0, 9.0)
.hover_image(self.imgs.search_btn_hover)
.press_image(self.imgs.search_btn_press)
.w_h(16.0, 16.0)
.set(state.ids.player_search_icon, ui)
.was_clicked()
{
events.push(Event::Focus(state.ids.player_search_input));
}
if let Some(string) =
TextEdit::new(self.show.social_search_key.as_deref().unwrap_or_default())
.top_left_with_margins_on(state.ids.player_search_icon, -1.0, 22.0)
.w_h(215.0, 20.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14))
.color(TEXT_COLOR)
.set(state.ids.player_search_input, ui)
{
events.push(Event::SearchPlayers(Some(string)));
}
Rectangle::fill_with([266.0, 20.0], color::TRANSPARENT)
.top_left_with_margins_on(state.ids.player_search_icon, -1.0, 0.0)
.graphics_for(state.ids.player_search_icon)
.set(state.ids.player_search_input_overlay, ui);
events events
} }