mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Widened recipe list in crafting menu and added quality indicators to names in the list
This commit is contained in:
parent
85b8d4e7c0
commit
39fc48ac17
@ -67,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Add chest to each dungeon with unique loot
|
- Add chest to each dungeon with unique loot
|
||||||
- Added a new option in the graphics menu to enable GPU timing (not always supported). The timing values can be viewed in the HUD debug info (F3) and will be saved as chrome trace files in the working directory when taking a screenshot.
|
- Added a new option in the graphics menu to enable GPU timing (not always supported). The timing values can be viewed in the HUD debug info (F3) and will be saved as chrome trace files in the working directory when taking a screenshot.
|
||||||
- Added new Present Mode option in the graphics menu. Selecting Fifo (i.e. vsync) or Mailbox can be used to eliminate screen tearing.
|
- Added new Present Mode option in the graphics menu. Selecting Fifo (i.e. vsync) or Mailbox can be used to eliminate screen tearing.
|
||||||
|
- Quality color indicators next to recipe names in crafting menu
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -121,6 +122,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Moved the rest of screenshot work into the background. Screenshoting no longer induces large pauses.
|
- Moved the rest of screenshot work into the background. Screenshoting no longer induces large pauses.
|
||||||
- Reworked tidal warrior to have unique attacks
|
- Reworked tidal warrior to have unique attacks
|
||||||
- Reworked yeti to have unique attacks
|
- Reworked yeti to have unique attacks
|
||||||
|
- Widened recipe name list in crafting menu
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
BIN
assets/voxygen/element/ui/crafting/crafting.png
(Stored with Git LFS)
BIN
assets/voxygen/element/ui/crafting/crafting.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/ui/crafting/crafting_frame.png
(Stored with Git LFS)
BIN
assets/voxygen/element/ui/crafting/crafting_frame.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/ui/crafting/quality_indicator.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/ui/crafting/quality_indicator.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
use super::{
|
use super::{
|
||||||
|
get_quality_col,
|
||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::{animate_by_pulse, ItemImgs, ItemKey::Tool},
|
item_imgs::{animate_by_pulse, ItemImgs, ItemKey::Tool},
|
||||||
Show, TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
Show, TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||||
@ -24,6 +25,7 @@ use common::{
|
|||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color, image,
|
color, image,
|
||||||
|
position::Dimension,
|
||||||
widget::{self, Button, Image, Rectangle, Scrollbar, Text, TextEdit},
|
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,
|
||||||
};
|
};
|
||||||
@ -52,7 +54,9 @@ widget_ids! {
|
|||||||
align_ing,
|
align_ing,
|
||||||
scrollbar_ing,
|
scrollbar_ing,
|
||||||
btn_craft,
|
btn_craft,
|
||||||
recipe_names[],
|
recipe_list_btns[],
|
||||||
|
recipe_list_labels[],
|
||||||
|
recipe_list_quality_indicators[],
|
||||||
recipe_img_frame[],
|
recipe_img_frame[],
|
||||||
recipe_img[],
|
recipe_img[],
|
||||||
ingredients[],
|
ingredients[],
|
||||||
@ -274,13 +278,13 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
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(456.0, 460.0)
|
||||||
.set(state.ids.window, ui);
|
.set(state.ids.window, ui);
|
||||||
// Window
|
// 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)
|
.wh_of(state.ids.window)
|
||||||
.set(state.ids.window_frame, ui);
|
.set(state.ids.window_frame, ui);
|
||||||
|
|
||||||
// Crafting Icon
|
// Crafting Icon
|
||||||
@ -310,7 +314,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
.set(state.ids.title_main, ui);
|
.set(state.ids.title_main, ui);
|
||||||
|
|
||||||
// Alignment
|
// Alignment
|
||||||
Rectangle::fill_with([136.0, 378.0], color::TRANSPARENT)
|
Rectangle::fill_with([170.0, 378.0], color::TRANSPARENT)
|
||||||
.top_left_with_margins_on(state.ids.window_frame, 74.0, 5.0)
|
.top_left_with_margins_on(state.ids.window_frame, 74.0, 5.0)
|
||||||
.scroll_kids_vertically()
|
.scroll_kids_vertically()
|
||||||
.set(state.ids.align_rec, ui);
|
.set(state.ids.align_rec, ui);
|
||||||
@ -398,12 +402,6 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
// 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)
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
enum RecipeIngredientQuantity {
|
|
||||||
All,
|
|
||||||
Some,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
let mut ordered_recipes: Vec<_> = self
|
let mut ordered_recipes: Vec<_> = self
|
||||||
.client
|
.client
|
||||||
.recipe_book()
|
.recipe_book()
|
||||||
@ -420,15 +418,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|(name, recipe)| {
|
.map(|(name, recipe)| {
|
||||||
let at_least_some_ingredients = recipe.inputs.iter().any(|(input, amount)| {
|
let is_craftable =
|
||||||
*amount > 0
|
|
||||||
&& self.inventory.slots().any(|slot| {
|
|
||||||
slot.as_ref()
|
|
||||||
.map(|item| item.matches_recipe_input(input))
|
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let show_craft_sprite =
|
|
||||||
self.client
|
self.client
|
||||||
.available_recipes()
|
.available_recipes()
|
||||||
.get(name.as_str())
|
.get(name.as_str())
|
||||||
@ -437,81 +427,112 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
Some(cs) == self.show.craft_sprite.map(|(_, s)| s)
|
Some(cs) == self.show.craft_sprite.map(|(_, s)| s)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let state = if show_craft_sprite {
|
(name, recipe, is_craftable)
|
||||||
RecipeIngredientQuantity::All
|
|
||||||
} else if at_least_some_ingredients {
|
|
||||||
RecipeIngredientQuantity::Some
|
|
||||||
} else {
|
|
||||||
RecipeIngredientQuantity::None
|
|
||||||
};
|
|
||||||
(name, recipe, state)
|
|
||||||
})
|
})
|
||||||
.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.quality(), recipe.output.0.name())
|
||||||
|
});
|
||||||
|
|
||||||
// Recipe list
|
// Recipe list
|
||||||
if state.ids.recipe_names.len() < self.client.recipe_book().iter().len() {
|
if state.ids.recipe_list_btns.len() < self.client.recipe_book().iter().len() {
|
||||||
state.update(|state| {
|
state.update(|state| {
|
||||||
state.ids.recipe_names.resize(
|
state.ids.recipe_list_btns.resize(
|
||||||
self.client.recipe_book().iter().len(),
|
self.client.recipe_book().iter().len(),
|
||||||
&mut ui.widget_id_generator(),
|
&mut ui.widget_id_generator(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (i, (name, recipe, quantity)) in ordered_recipes
|
if state.ids.recipe_list_labels.len() < self.client.recipe_book().iter().len() {
|
||||||
|
state.update(|state| {
|
||||||
|
state.ids.recipe_list_labels.resize(
|
||||||
|
self.client.recipe_book().iter().len(),
|
||||||
|
&mut ui.widget_id_generator(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if state.ids.recipe_list_quality_indicators.len() < self.client.recipe_book().iter().len() {
|
||||||
|
state.update(|state| {
|
||||||
|
state.ids.recipe_list_quality_indicators.resize(
|
||||||
|
self.client.recipe_book().iter().len(),
|
||||||
|
&mut ui.widget_id_generator(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (i, (name, recipe, is_craftable)) in ordered_recipes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, recipe, _)| self.show.crafting_tab.satisfies(recipe.output.0.as_ref()))
|
.filter(|(_, recipe, _)| self.show.crafting_tab.satisfies(recipe.output.0.as_ref()))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let button = Button::image(
|
let button = Button::image(if state.selected_recipe.as_ref() == Some(name) {
|
||||||
if state
|
self.imgs.selection
|
||||||
.selected_recipe
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s != name)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
self.imgs.nothing
|
|
||||||
} else {
|
|
||||||
match state.selected_recipe {
|
|
||||||
None => self.imgs.nothing,
|
|
||||||
Some(_) => self.imgs.selection,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
// Recipe Button
|
|
||||||
let button = if i == 0 {
|
|
||||||
button.mid_top_with_margin_on(state.ids.align_rec, 2.0)
|
|
||||||
} else {
|
} else {
|
||||||
button.mid_bottom_with_margin_on(state.ids.recipe_names[i - 1], -25.0)
|
self.imgs.nothing
|
||||||
};
|
})
|
||||||
let text_color = match quantity {
|
.and(|button| {
|
||||||
RecipeIngredientQuantity::All => TEXT_COLOR,
|
if i == 0 {
|
||||||
RecipeIngredientQuantity::Some => TEXT_GRAY_COLOR,
|
button.top_left_with_margins_on(state.ids.align_rec, 2.0, 7.0)
|
||||||
RecipeIngredientQuantity::None => TEXT_DULL_RED_COLOR,
|
} else {
|
||||||
|
button.down_from(state.ids.recipe_list_btns[i - 1], 5.0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.w(157.0)
|
||||||
|
.hover_image(self.imgs.selection_hover)
|
||||||
|
.press_image(self.imgs.selection_press);
|
||||||
|
|
||||||
|
let text = Text::new(recipe.output.0.name())
|
||||||
|
.color(if is_craftable {
|
||||||
|
TEXT_COLOR
|
||||||
|
} else {
|
||||||
|
TEXT_GRAY_COLOR
|
||||||
|
})
|
||||||
|
.font_size(self.fonts.cyri.scale(12))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.w(149.0)
|
||||||
|
.mid_top_with_margin_on(state.ids.recipe_list_btns[i], 3.0)
|
||||||
|
.graphics_for(state.ids.recipe_list_btns[i])
|
||||||
|
.center_justify();
|
||||||
|
|
||||||
|
let text_height = match text.get_y_dimension(ui) {
|
||||||
|
Dimension::Absolute(y) => y,
|
||||||
|
_ => 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if button
|
if button
|
||||||
.label(recipe.output.0.name())
|
.h((text_height + 7.0).max(20.0))
|
||||||
.w_h(130.0, 20.0)
|
.set(state.ids.recipe_list_btns[i], ui)
|
||||||
.hover_image(self.imgs.selection_hover)
|
|
||||||
.press_image(self.imgs.selection_press)
|
|
||||||
.label_color(text_color)
|
|
||||||
.label_font_size(self.fonts.cyri.scale(12))
|
|
||||||
.label_font_id(self.fonts.cyri.conrod_id)
|
|
||||||
.label_y(conrod_core::position::Relative::Scalar(2.0))
|
|
||||||
.set(state.ids.recipe_names[i], ui)
|
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
if state
|
if state.selected_recipe.as_ref() == Some(name) {
|
||||||
.selected_recipe
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s == name)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
state.update(|s| s.selected_recipe = None);
|
state.update(|s| s.selected_recipe = None);
|
||||||
} else {
|
} else {
|
||||||
state.update(|s| s.selected_recipe = Some(name.clone()));
|
state.update(|s| s.selected_recipe = Some(name.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// set the text here so that the correct position of the button is retrieved
|
||||||
|
text.set(state.ids.recipe_list_labels[i], ui);
|
||||||
|
|
||||||
|
// Sidebar color
|
||||||
|
let color::Hsla(h, s, l, _) = get_quality_col(recipe.output.0.as_ref()).to_hsl();
|
||||||
|
let val_multiplier = if is_craftable { 0.7 } else { 0.5 };
|
||||||
|
// Apply conversion to hsv, multiply v by the desired amount, then revert to
|
||||||
|
// hsl. Conversion formulae: https://en.wikipedia.org/wiki/HSL_and_HSV#Interconversion
|
||||||
|
// Note that division by 0 is not possible since none of the colours are black
|
||||||
|
// or white
|
||||||
|
let quality_col = color::hsl(
|
||||||
|
h,
|
||||||
|
s * val_multiplier * f32::min(l, 1.0 - l)
|
||||||
|
/ f32::min(l * val_multiplier, 1.0 - l * val_multiplier),
|
||||||
|
l * val_multiplier,
|
||||||
|
);
|
||||||
|
|
||||||
|
Button::image(self.imgs.quality_indicator)
|
||||||
|
.image_color(quality_col)
|
||||||
|
.h_of(state.ids.recipe_list_btns[i])
|
||||||
|
.w(4.0)
|
||||||
|
.left_from(state.ids.recipe_list_btns[i], 1.0)
|
||||||
|
.graphics_for(state.ids.recipe_list_btns[i])
|
||||||
|
.set(state.ids.recipe_list_quality_indicators[i], ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selected Recipe
|
// Selected Recipe
|
||||||
@ -877,7 +898,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::SearchRecipe(None));
|
events.push(Event::SearchRecipe(None));
|
||||||
}
|
}
|
||||||
Rectangle::fill([114.0, 20.0])
|
Rectangle::fill([148.0, 20.0])
|
||||||
.top_left_with_margins_on(state.ids.btn_close_search, -2.0, 16.0)
|
.top_left_with_margins_on(state.ids.btn_close_search, -2.0, 16.0)
|
||||||
.hsla(0.0, 0.0, 0.0, 0.7)
|
.hsla(0.0, 0.0, 0.0, 0.7)
|
||||||
.depth(1.0)
|
.depth(1.0)
|
||||||
@ -885,7 +906,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
.set(state.ids.input_bg_search, ui);
|
.set(state.ids.input_bg_search, ui);
|
||||||
if let Some(string) = TextEdit::new(key.as_str())
|
if let Some(string) = TextEdit::new(key.as_str())
|
||||||
.top_left_with_margins_on(state.ids.btn_close_search, -2.0, 18.0)
|
.top_left_with_margins_on(state.ids.btn_close_search, -2.0, 18.0)
|
||||||
.w_h(90.0, 20.0)
|
.w_h(124.0, 20.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)
|
||||||
@ -902,7 +923,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.parent(state.ids.window)
|
.parent(state.ids.window)
|
||||||
.set(state.ids.title_rec, ui);
|
.set(state.ids.title_rec, ui);
|
||||||
Rectangle::fill_with([114.0, 20.0], color::TRANSPARENT)
|
Rectangle::fill_with([148.0, 20.0], color::TRANSPARENT)
|
||||||
.top_left_with_margins_on(state.ids.window, 52.0, 26.0)
|
.top_left_with_margins_on(state.ids.window, 52.0, 26.0)
|
||||||
.graphics_for(state.ids.btn_open_search)
|
.graphics_for(state.ids.btn_open_search)
|
||||||
.set(state.ids.input_overlay_search, ui);
|
.set(state.ids.input_overlay_search, ui);
|
||||||
|
@ -96,6 +96,7 @@ image_ids! {
|
|||||||
crafting_icon: "voxygen.element.ui.generic.buttons.anvil",
|
crafting_icon: "voxygen.element.ui.generic.buttons.anvil",
|
||||||
crafting_icon_hover: "voxygen.element.ui.generic.buttons.anvil_hover",
|
crafting_icon_hover: "voxygen.element.ui.generic.buttons.anvil_hover",
|
||||||
crafting_icon_press: "voxygen.element.ui.generic.buttons.anvil_press",
|
crafting_icon_press: "voxygen.element.ui.generic.buttons.anvil_press",
|
||||||
|
quality_indicator: "voxygen.element.ui.crafting.quality_indicator",
|
||||||
icon_armor: "voxygen.element.ui.crafting.icons.armors",
|
icon_armor: "voxygen.element.ui.crafting.icons.armors",
|
||||||
icon_tools: "voxygen.element.ui.crafting.icons.crafting_tools",
|
icon_tools: "voxygen.element.ui.crafting.icons.crafting_tools",
|
||||||
icon_dismantle: "voxygen.element.ui.crafting.icons.dismantle",
|
icon_dismantle: "voxygen.element.ui.crafting.icons.dismantle",
|
||||||
|
@ -135,7 +135,7 @@ const DEBUFF_COLOR: Color = Color::Rgba(0.79, 0.19, 0.17, 1.0);
|
|||||||
|
|
||||||
// Item Quality Colors
|
// Item Quality Colors
|
||||||
const QUALITY_LOW: Color = Color::Rgba(0.41, 0.41, 0.41, 1.0); // Grey - Trash, can be sold to vendors
|
const QUALITY_LOW: Color = Color::Rgba(0.41, 0.41, 0.41, 1.0); // Grey - Trash, can be sold to vendors
|
||||||
const QUALITY_COMMON: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0); // No Color - Crafting mats, food, starting equipment, quest items (like keys), rewards for easy quests
|
const QUALITY_COMMON: Color = Color::Rgba(0.79, 1.00, 1.00, 1.0); // No Color - Crafting mats, food, starting equipment, quest items (like keys), rewards for easy quests
|
||||||
const QUALITY_MODERATE: Color = Color::Rgba(0.06, 0.69, 0.12, 1.0); // Green - Quest Rewards, commonly looted items from NPCs
|
const QUALITY_MODERATE: Color = Color::Rgba(0.06, 0.69, 0.12, 1.0); // Green - Quest Rewards, commonly looted items from NPCs
|
||||||
const QUALITY_HIGH: Color = Color::Rgba(0.18, 0.32, 0.9, 1.0); // Blue - Dungeon rewards, boss loot, rewards for hard quests
|
const QUALITY_HIGH: Color = Color::Rgba(0.18, 0.32, 0.9, 1.0); // Blue - Dungeon rewards, boss loot, rewards for hard quests
|
||||||
const QUALITY_EPIC: Color = Color::Rgba(0.58, 0.29, 0.93, 1.0); // Purple - Rewards for epic quests and very hard bosses
|
const QUALITY_EPIC: Color = Color::Rgba(0.58, 0.29, 0.93, 1.0); // Purple - Rewards for epic quests and very hard bosses
|
||||||
|
@ -19,6 +19,7 @@ pub use widgets::{
|
|||||||
image_slider::ImageSlider,
|
image_slider::ImageSlider,
|
||||||
ingame::{Ingame, Ingameable},
|
ingame::{Ingame, Ingameable},
|
||||||
item_tooltip::{ItemTooltip, ItemTooltipManager, ItemTooltipable},
|
item_tooltip::{ItemTooltip, ItemTooltipManager, ItemTooltipable},
|
||||||
|
outlined_text::OutlinedText,
|
||||||
radio_list::RadioList,
|
radio_list::RadioList,
|
||||||
slot,
|
slot,
|
||||||
toggle_button::ToggleButton,
|
toggle_button::ToggleButton,
|
||||||
|
@ -3,6 +3,7 @@ pub mod image_frame;
|
|||||||
pub mod image_slider;
|
pub mod image_slider;
|
||||||
pub mod ingame;
|
pub mod ingame;
|
||||||
pub mod item_tooltip;
|
pub mod item_tooltip;
|
||||||
|
pub mod outlined_text;
|
||||||
pub mod radio_list;
|
pub mod radio_list;
|
||||||
pub mod slot;
|
pub mod slot;
|
||||||
pub mod toggle_button;
|
pub mod toggle_button;
|
||||||
|
117
voxygen/src/ui/widgets/outlined_text.rs
Normal file
117
voxygen/src/ui/widgets/outlined_text.rs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
use conrod_core::{
|
||||||
|
builder_methods, text,
|
||||||
|
widget::{self, Text},
|
||||||
|
widget_ids, Color, FontSize, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, WidgetCommon)]
|
||||||
|
pub struct OutlinedText<'a> {
|
||||||
|
#[conrod(common_builder)]
|
||||||
|
common: widget::CommonBuilder,
|
||||||
|
|
||||||
|
text: &'a str,
|
||||||
|
text_style: widget::text::Style,
|
||||||
|
outline_color: Option<Color>,
|
||||||
|
outline_width: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_ids! {
|
||||||
|
struct Ids{
|
||||||
|
base,
|
||||||
|
outline1,
|
||||||
|
outline2,
|
||||||
|
outline3,
|
||||||
|
outline4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
ids: Ids,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> OutlinedText<'a> {
|
||||||
|
builder_methods! {
|
||||||
|
pub color {text_style.color = Some(Color)}
|
||||||
|
pub outline_color {outline_color = Some(Color)}
|
||||||
|
|
||||||
|
pub font_size {text_style.font_size = Some(FontSize)}
|
||||||
|
pub outline_width {outline_width = f64}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(text: &'a str) -> Self {
|
||||||
|
Self {
|
||||||
|
common: widget::CommonBuilder::default(),
|
||||||
|
text,
|
||||||
|
|
||||||
|
text_style: widget::text::Style::default(),
|
||||||
|
outline_color: None,
|
||||||
|
outline_width: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font_id(mut self, font_id: text::font::Id) -> Self {
|
||||||
|
self.text_style.font_id = Some(Some(font_id));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for OutlinedText<'a> {
|
||||||
|
type Event = ();
|
||||||
|
type State = State;
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||||
|
State {
|
||||||
|
ids: Ids::new(id_gen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_unit)] // TODO: Pending review in #587
|
||||||
|
fn style(&self) -> Self::Style { () }
|
||||||
|
|
||||||
|
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||||
|
let widget::UpdateArgs {
|
||||||
|
id,
|
||||||
|
state,
|
||||||
|
ui,
|
||||||
|
rect,
|
||||||
|
..
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
let mut outline_style = self.text_style;
|
||||||
|
outline_style.color = self.outline_color;
|
||||||
|
|
||||||
|
let shift = self.outline_width;
|
||||||
|
Text::new(self.text)
|
||||||
|
.with_style(self.text_style)
|
||||||
|
.xy(rect.xy())
|
||||||
|
.wh(rect.dim())
|
||||||
|
.parent(id)
|
||||||
|
.depth(-1.0)
|
||||||
|
.set(state.ids.base, ui);
|
||||||
|
|
||||||
|
Text::new(self.text)
|
||||||
|
.with_style(outline_style)
|
||||||
|
.x_y_relative_to(state.ids.base, shift, shift)
|
||||||
|
.wh_of(state.ids.base)
|
||||||
|
.set(state.ids.outline1, ui);
|
||||||
|
|
||||||
|
Text::new(self.text)
|
||||||
|
.with_style(outline_style)
|
||||||
|
.x_y_relative_to(state.ids.base, -shift, shift)
|
||||||
|
.wh_of(state.ids.base)
|
||||||
|
.set(state.ids.outline2, ui);
|
||||||
|
|
||||||
|
Text::new(self.text)
|
||||||
|
.with_style(outline_style)
|
||||||
|
.x_y_relative_to(state.ids.base, shift, -shift)
|
||||||
|
.wh_of(state.ids.base)
|
||||||
|
.set(state.ids.outline3, ui);
|
||||||
|
|
||||||
|
Text::new(self.text)
|
||||||
|
.with_style(outline_style)
|
||||||
|
.x_y_relative_to(state.ids.base, -shift, -shift)
|
||||||
|
.wh_of(state.ids.base)
|
||||||
|
.set(state.ids.outline4, ui);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user