mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Scale content image based on slot size, fix weapon images not showing, stop selection of empty slots
This commit is contained in:
parent
4c5f668203
commit
77948d27ca
@ -8,8 +8,9 @@ use super::{
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{
|
||||
fonts::ConrodVoxygenFonts, slot::SlotMaker, ImageFrame, Tooltip, TooltipManager,
|
||||
Tooltipable,
|
||||
fonts::ConrodVoxygenFonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
@ -318,8 +319,11 @@ impl<'a> Widget for Bag<'a> {
|
||||
filled_slot: self.imgs.armor_slot,
|
||||
selected_slot: self.imgs.armor_slot_sel,
|
||||
background_color: Some(UI_HIGHLIGHT_0),
|
||||
content_size: Vec2::broadcast(30.0),
|
||||
selected_content_size: Vec2::broadcast(32.0),
|
||||
content_size: ContentSize {
|
||||
width_height_ratio: 1.0,
|
||||
max_fraction: 0.75,
|
||||
},
|
||||
selected_content_scale: 1.067,
|
||||
amount_font: self.fonts.cyri.conrod_id,
|
||||
amount_margins: Vec2::new(-4.0, 0.0),
|
||||
amount_font_size: self.fonts.cyri.scale(12),
|
||||
@ -331,8 +335,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Head
|
||||
let (title, desc) = ("Helmet", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Head)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::Head, [45.0; 2])
|
||||
.mid_top_with_margin_on(state.ids.bg_frame, 60.0)
|
||||
.with_icon(self.imgs.head_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -340,8 +343,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Necklace
|
||||
let (title, desc) = ("Neck", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Neck)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::Neck, [45.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.head_slot, -55.0)
|
||||
.with_icon(self.imgs.necklace_bg, Vec2::new(40.0, 31.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -353,8 +355,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Chest", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Chest)
|
||||
.w_h(85.0, 85.0)
|
||||
.fabricate(ArmorSlot::Chest, [85.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.neck_slot, -95.0)
|
||||
.with_icon(self.imgs.chest_bg, Vec2::new(64.0, 42.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -365,8 +366,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Shoulders", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Shoulders)
|
||||
.w_h(70.0, 70.0)
|
||||
.fabricate(ArmorSlot::Shoulders, [70.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
||||
.with_icon(self.imgs.shoulders_bg, Vec2::new(60.0, 36.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -377,8 +377,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Hands", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Hands)
|
||||
.w_h(70.0, 70.0)
|
||||
.fabricate(ArmorSlot::Hands, [70.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
||||
.with_icon(self.imgs.hands_bg, Vec2::new(55.0, 60.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -389,8 +388,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Belt", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Belt)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::Belt, [45.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.chest_slot, -55.0)
|
||||
.with_icon(self.imgs.belt_bg, Vec2::new(40.0, 23.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -401,8 +399,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Legs", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Legs)
|
||||
.w_h(85.0, 85.0)
|
||||
.fabricate(ArmorSlot::Legs, [85.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.belt_slot, -95.0)
|
||||
.with_icon(self.imgs.legs_bg, Vec2::new(48.0, 70.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -410,8 +407,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Ring-L
|
||||
let (title, desc) = ("Left Ring", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::LeftRing)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::LeftRing, [45.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.shoulders_slot, -55.0, 0.0)
|
||||
.with_icon(self.imgs.ring_l_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -419,8 +415,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Ring-R
|
||||
let (title, desc) = ("Right Ring", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::RightRing)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::RightRing, [45.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.hands_slot, -55.0, 0.0)
|
||||
.with_icon(self.imgs.ring_r_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -428,8 +423,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Back
|
||||
let (title, desc) = ("Back", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Back)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::Back, [45.0; 2])
|
||||
.down_from(state.ids.ring_l_slot, 10.0)
|
||||
.with_icon(self.imgs.back_bg, Vec2::new(33.0, 40.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -440,8 +434,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.as_ref()
|
||||
.map_or(("Feet", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Feet)
|
||||
.w_h(45.0, 45.0)
|
||||
.fabricate(ArmorSlot::Feet, [45.0; 2])
|
||||
.down_from(state.ids.ring_r_slot, 10.0)
|
||||
.with_icon(self.imgs.feet_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -449,8 +442,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
// Tabard
|
||||
let (title, desc) = ("Tabard", "");
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Tabard)
|
||||
.w_h(70.0, 70.0)
|
||||
.fabricate(ArmorSlot::Tabard, [70.0; 2])
|
||||
.top_right_with_margins_on(state.ids.bg_frame, 80.5, 53.0)
|
||||
.with_icon(self.imgs.tabard_bg, Vec2::new(60.0, 60.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -462,8 +454,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.map(|i| &i.item)
|
||||
.map_or(("Mainhand", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Mainhand)
|
||||
.w_h(85.0, 85.0)
|
||||
.fabricate(ArmorSlot::Mainhand, [85.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.back_slot, -95.0, 0.0)
|
||||
.with_icon(self.imgs.mainhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -475,8 +466,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
.map(|i| &i.item)
|
||||
.map_or(("Offhand", ""), |item| (item.name(), item.description()));
|
||||
slot_maker
|
||||
.fabricate(ArmorSlot::Offhand)
|
||||
.w_h(85.0, 85.0)
|
||||
.fabricate(ArmorSlot::Offhand, [85.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.feet_slot, -95.0, 0.0)
|
||||
.with_icon(self.imgs.offhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
||||
.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip)
|
||||
@ -601,8 +591,11 @@ impl<'a> Widget for Bag<'a> {
|
||||
filled_slot: self.imgs.inv_slot,
|
||||
selected_slot: self.imgs.inv_slot_sel,
|
||||
background_color: Some(UI_MAIN),
|
||||
content_size: Vec2::broadcast(30.0),
|
||||
selected_content_size: Vec2::broadcast(32.0),
|
||||
content_size: ContentSize {
|
||||
width_height_ratio: 1.0,
|
||||
max_fraction: 0.75,
|
||||
},
|
||||
selected_content_scale: 1.067,
|
||||
amount_font: self.fonts.cyri.conrod_id,
|
||||
amount_margins: Vec2::new(-4.0, 0.0),
|
||||
amount_font_size: self.fonts.cyri.scale(12),
|
||||
@ -617,13 +610,12 @@ impl<'a> Widget for Bag<'a> {
|
||||
|
||||
// Slot
|
||||
let slot_widget = slot_maker
|
||||
.fabricate(InventorySlot(i))
|
||||
.fabricate(InventorySlot(i), [40.0; 2])
|
||||
.top_left_with_margins_on(
|
||||
state.ids.inv_alignment,
|
||||
0.0 + y as f64 * (40.0),
|
||||
0.0 + x as f64 * (40.0),
|
||||
)
|
||||
.wh([40.0; 2]);
|
||||
);
|
||||
if let Some(item) = item {
|
||||
slot_widget
|
||||
.with_tooltip(
|
||||
|
@ -86,6 +86,8 @@ impl ContentKey for ArmorSlot {
|
||||
ArmorSlot::Hands => source.hand.as_ref(),
|
||||
ArmorSlot::Legs => source.pants.as_ref(),
|
||||
ArmorSlot::Feet => source.foot.as_ref(),
|
||||
ArmorSlot::Mainhand => source.active_item.as_ref().map(|i| &i.item),
|
||||
ArmorSlot::Offhand => source.second_item.as_ref().map(|i| &i.item),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
@ -22,14 +22,22 @@ pub trait ContentKey: Copy {
|
||||
|
||||
pub trait SlotKinds: Sized + PartialEq + Copy {}
|
||||
|
||||
pub struct ContentSize {
|
||||
// Width divided by height
|
||||
pub width_height_ratio: f32,
|
||||
// Max fraction of slot widget size that each side can be
|
||||
pub max_fraction: f32,
|
||||
}
|
||||
|
||||
pub struct SlotMaker<'a, C: ContentKey + Into<K>, K: SlotKinds> {
|
||||
pub empty_slot: image::Id,
|
||||
pub filled_slot: image::Id,
|
||||
pub selected_slot: image::Id,
|
||||
// Is this useful?
|
||||
pub background_color: Option<Color>,
|
||||
pub content_size: Vec2<f32>,
|
||||
pub selected_content_size: Vec2<f32>,
|
||||
pub content_size: ContentSize,
|
||||
// How to scale content size relative to base content size when selected
|
||||
pub selected_content_scale: f32,
|
||||
pub amount_font: font::Id,
|
||||
pub amount_font_size: u32,
|
||||
pub amount_margins: Vec2<f32>,
|
||||
@ -44,14 +52,29 @@ where
|
||||
C: ContentKey + Into<K>,
|
||||
K: SlotKinds,
|
||||
{
|
||||
pub fn fabricate(&mut self, contents: C) -> Slot<C, K> {
|
||||
pub fn fabricate(&mut self, contents: C, wh: [f32; 2]) -> Slot<C, K> {
|
||||
let content_size = {
|
||||
let ContentSize {
|
||||
max_fraction,
|
||||
width_height_ratio,
|
||||
} = self.content_size;
|
||||
let w_max = max_fraction * wh[0];
|
||||
let h_max = max_fraction * wh[1];
|
||||
let max_ratio = w_max / h_max;
|
||||
let (w, h) = if max_ratio > width_height_ratio {
|
||||
(width_height_ratio * h_max, w_max)
|
||||
} else {
|
||||
(w_max, w_max / width_height_ratio)
|
||||
};
|
||||
Vec2::new(w, h)
|
||||
};
|
||||
Slot::new(
|
||||
contents,
|
||||
self.empty_slot,
|
||||
self.filled_slot,
|
||||
self.selected_slot,
|
||||
self.content_size,
|
||||
self.selected_content_size,
|
||||
content_size,
|
||||
self.selected_content_scale,
|
||||
self.amount_font,
|
||||
self.amount_font_size,
|
||||
self.amount_margins,
|
||||
@ -59,6 +82,7 @@ where
|
||||
self.content_source,
|
||||
self.image_source,
|
||||
)
|
||||
.wh([wh[0] as f64, wh[1] as f64])
|
||||
.and_then(self.background_color, |s, c| s.with_background_color(c))
|
||||
.and_then(self.slot_manager.as_mut(), |s, m| s.with_manager(m))
|
||||
}
|
||||
@ -150,7 +174,23 @@ where
|
||||
std::mem::replace(&mut self.events, Vec::new())
|
||||
}
|
||||
|
||||
fn update(&mut self, widget: widget::Id, slot: K, ui: &conrod_core::Ui) -> Interaction {
|
||||
fn update(
|
||||
&mut self,
|
||||
widget: widget::Id,
|
||||
slot: K,
|
||||
ui: &conrod_core::Ui,
|
||||
filled: bool,
|
||||
) -> Interaction {
|
||||
// If the slot is no longer filled deselect it or cancel dragging
|
||||
match &self.state {
|
||||
ManagerState::Selected(id, _) | ManagerState::Dragging(id, _)
|
||||
if *id == widget && !filled =>
|
||||
{
|
||||
self.state = ManagerState::Idle;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// If this is the selected/dragged widget make sure the slot value is up to date
|
||||
match &mut self.state {
|
||||
ManagerState::Selected(id, stored_slot) | ManagerState::Dragging(id, stored_slot)
|
||||
@ -163,7 +203,6 @@ where
|
||||
|
||||
// TODO: make more robust wrt multiple events in the same frame (eg event order
|
||||
// may matter) TODO: handle taps as well
|
||||
// TODO: handle clicks in empty space
|
||||
// TODO: handle drags
|
||||
let click_count = ui.widget_input(widget).clicks().left().count();
|
||||
if click_count > 0 {
|
||||
@ -192,7 +231,7 @@ where
|
||||
}
|
||||
} else {
|
||||
// No widgets were selected
|
||||
if odd_num_clicks {
|
||||
if odd_num_clicks && filled {
|
||||
ManagerState::Selected(widget, slot)
|
||||
} else {
|
||||
// Selected and then deselected with one or more clicks
|
||||
@ -222,8 +261,7 @@ pub struct Slot<'a, C: ContentKey + Into<K>, K: SlotKinds> {
|
||||
|
||||
// Size of content image
|
||||
content_size: Vec2<f32>,
|
||||
// TODO: maybe use constant scale factor or move this setting to the slot manager?
|
||||
selected_content_size: Vec2<f32>,
|
||||
selected_content_scale: f32,
|
||||
|
||||
icon: Option<(image::Id, Vec2<f32>, Option<Color>)>,
|
||||
|
||||
@ -280,7 +318,7 @@ where
|
||||
filled_slot: image::Id,
|
||||
selected_slot: image::Id,
|
||||
content_size: Vec2<f32>,
|
||||
selected_content_size: Vec2<f32>,
|
||||
selected_content_scale: f32,
|
||||
amount_font: font::Id,
|
||||
amount_font_size: u32,
|
||||
amount_margins: Vec2<f32>,
|
||||
@ -295,7 +333,7 @@ where
|
||||
selected_slot,
|
||||
background_color: None,
|
||||
content_size,
|
||||
selected_content_size,
|
||||
selected_content_scale,
|
||||
icon: None,
|
||||
amount_font,
|
||||
amount_font_size,
|
||||
@ -343,7 +381,7 @@ where
|
||||
selected_slot,
|
||||
background_color,
|
||||
content_size,
|
||||
selected_content_size,
|
||||
selected_content_scale,
|
||||
icon,
|
||||
amount_font,
|
||||
amount_font_size,
|
||||
@ -366,9 +404,9 @@ where
|
||||
}
|
||||
|
||||
// Get whether this slot is selected
|
||||
let interaction = self
|
||||
.slot_manager
|
||||
.map_or(Interaction::None, |m| m.update(id, content.into(), ui));
|
||||
let interaction = self.slot_manager.map_or(Interaction::None, |m| {
|
||||
m.update(id, content.into(), ui, state.cached_image.is_some())
|
||||
});
|
||||
|
||||
// Get image ids
|
||||
let content_image = state.cached_image.as_ref().map(|c| c.1);
|
||||
@ -412,11 +450,12 @@ where
|
||||
if let Some(content_image) = content_image {
|
||||
Image::new(content_image)
|
||||
.x_y(x, y)
|
||||
.wh(if let Interaction::Selected = interaction {
|
||||
selected_content_size
|
||||
} else {
|
||||
content_size
|
||||
}
|
||||
.wh((content_size
|
||||
* if let Interaction::Selected = interaction {
|
||||
selected_content_scale
|
||||
} else {
|
||||
1.0
|
||||
})
|
||||
.map(|e| e as f64)
|
||||
.into_array())
|
||||
.parent(id)
|
||||
|
Loading…
Reference in New Issue
Block a user