diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs index 4bcb2fd991..0cf96acc5a 100644 --- a/voxygen/src/hud/bag.rs +++ b/voxygen/src/hud/bag.rs @@ -21,7 +21,7 @@ use common::{ combat::{combat_rating, Damage}, comp::{ inventory::InventorySortOrder, - item::{ItemDef, MaterialStatManifest, Quality}, + item::{Item, ItemDef, ItemDesc, MaterialStatManifest, Quality}, Body, Energy, Health, Inventory, Poise, SkillSet, Stats, }, }; @@ -383,6 +383,20 @@ impl<'a> InventoryScroller<'a> { .as_ref() .and_then(|(_, _, prices)| prices.clone()); + let salvage_result: Vec = item + .salvage_output() + .map(|asset| Item::new_from_asset_expect(asset)) + .collect(); + + let item: Vec<&dyn ItemDesc> = if self.show_salvage { + salvage_result + .iter() + .map(|item| item as &dyn ItemDesc) + .collect() + } else { + vec![item] + }; + slot_widget .filled_slot(quality_col_img) .with_item_tooltip( @@ -851,7 +865,7 @@ impl<'a> Widget for Bag<'a> { if let Some(item) = inventory.equipped($slot) { let manager = &mut *self.item_tooltip_manager; $slot_maker - .with_item_tooltip(manager, item, &None, &item_tooltip) + .with_item_tooltip(manager, vec![item], &None, &item_tooltip) .set($slot_id, ui) } else { let manager = &mut *self.tooltip_manager; diff --git a/voxygen/src/hud/crafting.rs b/voxygen/src/hud/crafting.rs index 9d9e531f79..0ae79ca579 100644 --- a/voxygen/src/hud/crafting.rs +++ b/voxygen/src/hud/crafting.rs @@ -724,7 +724,7 @@ impl<'a> Widget for Crafting<'a> { .middle_of(state.ids.output_img_frame) .with_item_tooltip( self.item_tooltip_manager, - &*recipe.output.0, + vec![&*recipe.output.0], &None, &item_tooltip, ) @@ -953,7 +953,7 @@ impl<'a> Widget for Crafting<'a> { .w_h(22.0, 22.0) .middle_of(state.ids.ingredient_frame[i]) .hover_image(self.imgs.wpn_icon_border_mo) - .with_item_tooltip(self.item_tooltip_manager, &*item_def, &None, &item_tooltip) + .with_item_tooltip(self.item_tooltip_manager, vec![&*item_def], &None, &item_tooltip) .set(state.ids.ingredient_btn[i], ui) .was_clicked() { @@ -968,6 +968,12 @@ impl<'a> Widget for Crafting<'a> { .middle_of(state.ids.ingredient_btn[i]) .w_h(20.0, 20.0) .graphics_for(state.ids.ingredient_btn[i]) + .with_item_tooltip( + self.item_tooltip_manager, + vec![&*item_def], + &None, + &item_tooltip, + ) .set(state.ids.ingredient_img[i], ui); // Ingredients text and amount diff --git a/voxygen/src/hud/loot_scroller.rs b/voxygen/src/hud/loot_scroller.rs index 53e88d6820..4654c56193 100644 --- a/voxygen/src/hud/loot_scroller.rs +++ b/voxygen/src/hud/loot_scroller.rs @@ -333,7 +333,12 @@ impl<'a> Widget for LootScroller<'a> { .color(Some(shade_color(color::hsla(0.0, 0.0, 1.0, 1.0)))) .w_h(ICON_SIZE, ICON_SIZE) .middle_of(state.ids.message_icon_bgs[i]) - .with_item_tooltip(self.item_tooltip_manager, &**item, &None, &item_tooltip) + .with_item_tooltip( + self.item_tooltip_manager, + vec![&**item], + &None, + &item_tooltip, + ) .set(state.ids.message_icons[i], ui); let label = if *amount == 1 { diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 71362c9b51..5183d036bf 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -645,7 +645,7 @@ impl<'a> Skillbar<'a> { .position(entry.position); // if there is an item attached, show item tooltip if let Some(item) = slot_content(entry.slot) { - slot.with_item_tooltip(self.item_tooltip_manager, item, &None, &item_tooltip) + slot.with_item_tooltip(self.item_tooltip_manager, vec![item], &None, &item_tooltip) .set(entry.widget_id, ui); // if we can gather some text to display, show it } else if let Some((title, desc)) = tooltip_text(entry.slot) { diff --git a/voxygen/src/hud/trade.rs b/voxygen/src/hud/trade.rs index 8eaede4b0b..e4b1f1b89a 100644 --- a/voxygen/src/hud/trade.rs +++ b/voxygen/src/hud/trade.rs @@ -393,7 +393,7 @@ impl<'a> Trade<'a> { slot_widget .filled_slot(quality_col_img) - .with_item_tooltip(self.item_tooltip_manager, item, prices, &item_tooltip) + .with_item_tooltip(self.item_tooltip_manager, vec![item], prices, &item_tooltip) .set(slot_id, ui); } else { slot_widget.set(slot_id, ui); diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 83b04859e0..ce29fa2cc9 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -157,7 +157,6 @@ impl Ui { ui.set_num_redraw_frames(1); let item_tooltip_manager = ItemTooltipManager::new( - ui.widget_id_generator(), Duration::from_millis(1), Duration::from_millis(0), scale.scale_factor_logical(), diff --git a/voxygen/src/ui/widgets/item_tooltip.rs b/voxygen/src/ui/widgets/item_tooltip.rs index 3992212248..a6afc65f7d 100644 --- a/voxygen/src/ui/widgets/item_tooltip.rs +++ b/voxygen/src/ui/widgets/item_tooltip.rs @@ -40,7 +40,6 @@ enum HoverState { const MOUSE_PAD_Y: f64 = 15.0; pub struct ItemTooltipManager { - tooltip_id: widget::Id, state: HoverState, // How long before a tooltip is displayed when hovering hover_dur: Duration, @@ -51,14 +50,8 @@ pub struct ItemTooltipManager { } impl ItemTooltipManager { - pub fn new( - mut generator: widget::id::Generator, - hover_dur: Duration, - fade_dur: Duration, - logical_scale_factor: f64, - ) -> Self { + pub fn new(hover_dur: Duration, fade_dur: Duration, logical_scale_factor: f64) -> Self { Self { - tooltip_id: generator.next(), state: HoverState::None, hover_dur, fade_dur, @@ -115,63 +108,72 @@ impl ItemTooltipManager { fn set_tooltip( &mut self, tooltip: &ItemTooltip, - item: &dyn ItemDesc, + items: Vec<&dyn ItemDesc>, prices: &Option, img_id: Option, image_dims: Option<(f64, f64)>, src_id: widget::Id, ui: &mut UiCell, ) { - let tooltip_id = self.tooltip_id; + let mut y_offset = 0.0; let mp_h = MOUSE_PAD_Y / self.logical_scale_factor; + for item in items { + let tooltip_id = ui.widget_id_generator().next(); - let tooltip = |transparency, mouse_pos: [f64; 2], ui: &mut UiCell| { - // Fill in text and the potential image beforehand to get an accurate size for - // spacing - let tooltip = tooltip - .clone() - .item(item) - .prices(prices) - .image(img_id) - .image_dims(image_dims); + let mut tooltip = |transparency, mouse_pos: [f64; 2], ui: &mut UiCell| { + // Fill in text and the potential image beforehand to get an accurate size for + // spacing + let tooltip = tooltip + .clone() + .item(item) + .prices(prices) + .image(img_id) + .image_dims(image_dims); - let [t_w, t_h] = tooltip.get_wh(ui).unwrap_or([0.0, 0.0]); - let [m_x, m_y] = [mouse_pos[0], mouse_pos[1]]; - let (w_w, w_h) = (ui.win_w, ui.win_h); + let [t_w, t_h] = tooltip.get_wh(ui).unwrap_or([0.0, 0.0]); + let [m_x, m_y] = [mouse_pos[0], mouse_pos[1]]; + let (w_w, w_h) = (ui.win_w, ui.win_h); - // Determine position based on size and mouse position - // Flow to the top left of the mouse when there is space - let x = if (m_x + w_w / 2.0) > t_w { - m_x - t_w / 2.0 - } else { - m_x + t_w / 2.0 + // Determine position based on size and mouse position + // Flow to the top left of the mouse when there is space + let x = if (m_x + w_w / 2.0) > t_w { + m_x - t_w / 2.0 + } else { + m_x + t_w / 2.0 + }; + let y = if w_h - (m_y + w_h / 2.0) > t_h + mp_h { + m_y + mp_h + t_h / 2.0 + } else { + m_y - mp_h - t_h / 2.0 + }; + tooltip + .floating(true) + .transparency(transparency) + .x_y(x, y + y_offset) + .set(tooltip_id, ui); + + // Increase the offset to stack the next tooltip on top of the previous one + y_offset += t_h + 5.0; }; - let y = if w_h - (m_y + w_h / 2.0) > t_h + mp_h { - m_y + mp_h + t_h / 2.0 - } else { - m_y - mp_h - t_h / 2.0 - }; - tooltip - .floating(true) - .transparency(transparency) - .x_y(x, y) - .set(tooltip_id, ui); - }; - match self.state { - HoverState::Hovering(Hover(id, xy)) if id == src_id => tooltip(1.0, xy, ui), - HoverState::Fading(start, Hover(id, xy), _) if id == src_id => tooltip( - (0.1f32 - start.elapsed().as_millis() as f32 / self.hover_dur.as_millis() as f32) - .max(0.0), - xy, - ui, - ), - HoverState::Start(start, id) if id == src_id && start.elapsed() > self.hover_dur => { - let xy = ui.global_input().current.mouse.xy; - self.state = HoverState::Hovering(Hover(id, xy)); - tooltip(1.0, xy, ui); - }, - _ => (), + match self.state { + HoverState::Hovering(Hover(id, xy)) if id == src_id => tooltip(1.0, xy, ui), + HoverState::Fading(start, Hover(id, xy), _) if id == src_id => tooltip( + (0.1f32 + - start.elapsed().as_millis() as f32 / self.hover_dur.as_millis() as f32) + .max(0.0), + xy, + ui, + ), + HoverState::Start(start, id) + if id == src_id && start.elapsed() > self.hover_dur => + { + let xy = ui.global_input().current.mouse.xy; + self.state = HoverState::Hovering(Hover(id, xy)); + tooltip(1.0, xy, ui); + } + _ => (), + } } } } @@ -180,7 +182,7 @@ pub struct ItemTooltipped<'a, W> { inner: W, tooltip_manager: &'a mut ItemTooltipManager, - item: &'a dyn ItemDesc, + items: Vec<&'a dyn ItemDesc>, prices: &'a Option, img_id: Option, image_dims: Option<(f64, f64)>, @@ -201,7 +203,7 @@ impl<'a, W: Widget> ItemTooltipped<'a, W> { let event = self.inner.set(id, ui); self.tooltip_manager.set_tooltip( self.tooltip, - self.item, + self.items, self.prices, self.img_id, self.image_dims, @@ -218,7 +220,7 @@ pub trait ItemTooltipable { self, tooltip_manager: &'a mut ItemTooltipManager, - item: &'a dyn ItemDesc, + items: Vec<&'a dyn ItemDesc>, prices: &'a Option, @@ -231,14 +233,14 @@ impl ItemTooltipable for W { fn with_item_tooltip<'a>( self, tooltip_manager: &'a mut ItemTooltipManager, - item: &'a dyn ItemDesc, + items: Vec<&'a dyn ItemDesc>, prices: &'a Option, tooltip: &'a ItemTooltip<'a>, ) -> ItemTooltipped<'a, W> { ItemTooltipped { inner: self, tooltip_manager, - item, + items, prices, img_id: None, image_dims: None,