From 66b4c0d529b439dfa72d3750773ce3b499b0cadf Mon Sep 17 00:00:00 2001 From: Imbris Date: Mon, 6 Apr 2020 11:25:45 -0400 Subject: [PATCH] rework slot trait --- voxygen/src/hud/bag.rs | 6 +- voxygen/src/hud/mod.rs | 28 ++--- voxygen/src/hud/{slot_kinds.rs => slots.rs} | 70 +++++++----- voxygen/src/ui/widgets/slot.rs | 116 ++++++++++---------- 4 files changed, 115 insertions(+), 105 deletions(-) rename voxygen/src/hud/{slot_kinds.rs => slots.rs} (57%) diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs index fed6a7e0fc..d7d54e61e3 100644 --- a/voxygen/src/hud/bag.rs +++ b/voxygen/src/hud/bag.rs @@ -1,7 +1,7 @@ use super::{ img_ids::{Imgs, ImgsRot}, item_imgs::ItemImgs, - slot_kinds::{ArmorSlot, HudSlotManager, InventorySlot}, + slots::{ArmorSlot, InventorySlot, SlotManager}, Event as HudEvent, Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, XP_COLOR, }; @@ -91,7 +91,7 @@ pub struct Bag<'a> { common: widget::CommonBuilder, rot_imgs: &'a ImgsRot, tooltip_manager: &'a mut TooltipManager, - slot_manager: &'a mut HudSlotManager, + slot_manager: &'a mut SlotManager, _pulse: f32, localized_strings: &'a std::sync::Arc, @@ -107,7 +107,7 @@ impl<'a> Bag<'a> { fonts: &'a ConrodVoxygenFonts, rot_imgs: &'a ImgsRot, tooltip_manager: &'a mut TooltipManager, - slot_manager: &'a mut HudSlotManager, + slot_manager: &'a mut SlotManager, pulse: f32, localized_strings: &'a std::sync::Arc, stats: &'a Stats, diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 53cc3e70b7..44eaea390f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -8,7 +8,7 @@ mod map; mod minimap; mod settings_window; mod skillbar; -mod slot_kinds; +mod slots; mod social; mod spell; @@ -234,8 +234,8 @@ pub enum Event { CharacterSelection, UseInventorySlot(usize), SwapInventorySlots(usize, usize), - SwapInventoryArmor(usize, slot_kinds::ArmorSlot), - SwapArmorSlots(slot_kinds::ArmorSlot, slot_kinds::ArmorSlot), + SwapInventoryArmor(usize, slots::ArmorSlot), + SwapArmorSlots(slots::ArmorSlot, slots::ArmorSlot), DropInventorySlot(usize), Logout, Quit, @@ -443,7 +443,7 @@ pub struct Hud { pulse: f32, velocity: f32, voxygen_i18n: std::sync::Arc, - slot_manager: slot_kinds::HudSlotManager, + slot_manager: slots::SlotManager, } impl Hud { @@ -474,8 +474,7 @@ impl Hud { let fonts = ConrodVoxygenFonts::load(&voxygen_i18n.fonts, &mut ui) .expect("Impossible to load fonts!"); - let slot_manager = - slot_kinds::HudSlotManager::new(ui.id_generator(), Vec2::broadcast(40.0)); + let slot_manager = slots::SlotManager::new(ui.id_generator(), Vec2::broadcast(40.0)); Self { ui, @@ -1962,29 +1961,26 @@ impl Hud { // Maintain slot manager for event in self.slot_manager.maintain(ui_widgets) { - use slot_kinds::HudSlotKinds; + use slots::SlotKind; match event { - slot::Event::Dragged( - HudSlotKinds::Inventory(from), - HudSlotKinds::Inventory(to), - ) => { + slot::Event::Dragged(SlotKind::Inventory(from), SlotKind::Inventory(to)) => { // Swap between inventory slots events.push(Event::SwapInventorySlots(from.0, to.0)); }, - slot::Event::Dragged(HudSlotKinds::Armor(from), HudSlotKinds::Armor(to)) => { + slot::Event::Dragged(SlotKind::Armor(from), SlotKind::Armor(to)) => { // Swap between two armor slots events.push(Event::SwapArmorSlots(from, to)); }, - slot::Event::Dragged(HudSlotKinds::Inventory(inv), HudSlotKinds::Armor(arm)) - | slot::Event::Dragged(HudSlotKinds::Armor(arm), HudSlotKinds::Inventory(inv)) => { + slot::Event::Dragged(SlotKind::Inventory(inv), SlotKind::Armor(arm)) + | slot::Event::Dragged(SlotKind::Armor(arm), SlotKind::Inventory(inv)) => { // Swap between inventory and armor slot events.push(Event::SwapInventoryArmor(inv.0, arm)); }, - slot::Event::Dropped(HudSlotKinds::Inventory(from)) => { + slot::Event::Dropped(SlotKind::Inventory(from)) => { // Drop item from inventory events.push(Event::DropInventorySlot(from.0)); }, - slot::Event::Used(HudSlotKinds::Inventory(inv)) => { + slot::Event::Used(SlotKind::Inventory(inv)) => { // Item in inventory used (selected and then clicked again) events.push(Event::UseInventorySlot(inv.0)); }, diff --git a/voxygen/src/hud/slot_kinds.rs b/voxygen/src/hud/slots.rs similarity index 57% rename from voxygen/src/hud/slot_kinds.rs rename to voxygen/src/hud/slots.rs index 6dcf3d260d..398abca975 100644 --- a/voxygen/src/hud/slot_kinds.rs +++ b/voxygen/src/hud/slots.rs @@ -1,17 +1,17 @@ use super::item_imgs::{ItemImgs, ItemKey}; -use crate::ui::slot::{ContentKey, SlotKinds, SlotManager}; +use crate::ui::slot::{self, SlotKey, SumSlot}; use common::comp::{item::ItemKind, Inventory, Loadout}; use conrod_core::image; #[derive(Clone, Copy, PartialEq)] -pub enum HudSlotKinds { +pub enum SlotKind { Inventory(InventorySlot), Armor(ArmorSlot), - Hotbar(HotbarSlot), - //Spellbook(SpellbookSlot), TODO + /*Hotbar(HotbarSlot), + *Spellbook(SpellbookSlot), TODO */ } -pub type HudSlotManager = SlotManager; +pub type SlotManager = slot::SlotManager; #[derive(Clone, Copy, PartialEq)] pub struct InventorySlot(pub usize); @@ -34,7 +34,7 @@ pub enum ArmorSlot { Tabard, } -#[derive(Clone, Copy, PartialEq)] +/*#[derive(Clone, Copy, PartialEq)] pub enum HotbarSlot { One, Two, @@ -46,18 +46,16 @@ pub enum HotbarSlot { Eight, Nine, Ten, -} +}*/ -impl ContentKey for InventorySlot { - type ContentSource = Inventory; +impl SlotKey for InventorySlot { type ImageKey = ItemKey; - type ImageSource = ItemImgs; - fn image_key(&self, source: &Self::ContentSource) -> Option { + fn image_key(&self, source: &Inventory) -> Option { source.get(self.0).map(Into::into) } - fn amount(&self, source: &Self::ContentSource) -> Option { + fn amount(&self, source: &Inventory) -> Option { source .get(self.0) .and_then(|item| match item.kind { @@ -69,17 +67,15 @@ impl ContentKey for InventorySlot { .filter(|amount| *amount > 1) } - fn image_id(key: &Self::ImageKey, source: &Self::ImageSource) -> image::Id { + fn image_id(key: &Self::ImageKey, source: &ItemImgs) -> image::Id { source.img_id_or_not_found_img(key.clone()) } } -impl ContentKey for ArmorSlot { - type ContentSource = Loadout; +impl SlotKey for ArmorSlot { type ImageKey = ItemKey; - type ImageSource = ItemImgs; - fn image_key(&self, source: &Self::ContentSource) -> Option { + fn image_key(&self, source: &Loadout) -> Option { let item = match self { ArmorSlot::Shoulders => source.shoulder.as_ref(), ArmorSlot::Chest => source.chest.as_ref(), @@ -101,23 +97,47 @@ impl ContentKey for ArmorSlot { item.map(Into::into) } - fn amount(&self, _: &Self::ContentSource) -> Option { None } + fn amount(&self, _: &Loadout) -> Option { None } - fn image_id(key: &Self::ImageKey, source: &Self::ImageSource) -> image::Id { + fn image_id(key: &Self::ImageKey, source: &ItemImgs) -> image::Id { source.img_id_or_not_found_img(key.clone()) } } -impl From for HudSlotKinds { +/*impl SlotKey for HotbarSlot { + type ImageKey = ItemKey; + + fn image_key(&self, source: &Inventory) -> Option { + source.get(self.0).map(Into::into) + } + + fn amount(&self, source: &Inventory) -> Option { + source + .get(self.0) + .and_then(|item| match item.kind { + ItemKind::Tool { .. } | ItemKind::Armor { .. } => None, + ItemKind::Utility { amount, .. } + | ItemKind::Consumable { amount, .. } + | ItemKind::Ingredient { amount, .. } => Some(amount), + }) + .filter(|amount| *amount > 1) + } + + fn image_id(key: &Self::ImageKey, source: &ItemImgs) -> image::Id { + source.img_id_or_not_found_img(key.clone()) + } +}*/ + +impl From for SlotKind { fn from(inventory: InventorySlot) -> Self { Self::Inventory(inventory) } } -impl From for HudSlotKinds { +impl From for SlotKind { fn from(armor: ArmorSlot) -> Self { Self::Armor(armor) } } -impl From for HudSlotKinds { - fn from(hotbar: HotbarSlot) -> Self { Self::Hotbar(hotbar) } -} +//impl From for SlotKind { +// fn from(hotbar: HotbarSlot) -> Self { Self::Hotbar(hotbar) } +//} -impl SlotKinds for HudSlotKinds {} +impl SumSlot for SlotKind {} diff --git a/voxygen/src/ui/widgets/slot.rs b/voxygen/src/ui/widgets/slot.rs index ff7ab353de..59576ce5b3 100644 --- a/voxygen/src/ui/widgets/slot.rs +++ b/voxygen/src/ui/widgets/slot.rs @@ -10,18 +10,15 @@ use vek::*; const AMOUNT_SHADOW_OFFSET: [f64; 2] = [1.0, 1.0]; -pub trait ContentKey: Copy { - type ContentSource; - type ImageSource; +pub trait SlotKey: Copy { type ImageKey: PartialEq + Send + 'static; /// Returns an Option since the slot could be empty - fn image_key(&self, source: &Self::ContentSource) -> Option; - // TODO: is this the right integer type? - fn amount(&self, source: &Self::ContentSource) -> Option; - fn image_id(key: &Self::ImageKey, source: &Self::ImageSource) -> image::Id; + fn image_key(&self, source: &C) -> Option; + fn amount(&self, source: &C) -> Option; + fn image_id(key: &Self::ImageKey, source: &I) -> image::Id; } -pub trait SlotKinds: Sized + PartialEq + Copy + Send + 'static {} +pub trait SumSlot: Sized + PartialEq + Copy + Send + 'static {} pub struct ContentSize { // Width divided by height @@ -30,7 +27,7 @@ pub struct ContentSize { pub max_fraction: f32, } -pub struct SlotMaker<'a, C: ContentKey + Into, K: SlotKinds> { +pub struct SlotMaker<'a, C, I, S: SumSlot> { pub empty_slot: image::Id, pub filled_slot: image::Id, pub selected_slot: image::Id, @@ -43,17 +40,20 @@ pub struct SlotMaker<'a, C: ContentKey + Into, K: SlotKinds> { pub amount_font_size: u32, pub amount_margins: Vec2, pub amount_text_color: Color, - pub content_source: &'a C::ContentSource, - pub image_source: &'a C::ImageSource, - pub slot_manager: Option<&'a mut SlotManager>, + pub content_source: &'a C, + pub image_source: &'a I, + pub slot_manager: Option<&'a mut SlotManager>, } -impl<'a, C, K> SlotMaker<'a, C, K> +impl<'a, C, I, S> SlotMaker<'a, C, I, S> where - C: ContentKey + Into, - K: SlotKinds, + S: SumSlot, { - pub fn fabricate(&mut self, contents: C, wh: [f32; 2]) -> Slot { + pub fn fabricate + Into>( + &mut self, + contents: K, + wh: [f32; 2], + ) -> Slot { let content_size = { let ContentSize { max_fraction, @@ -111,13 +111,13 @@ pub enum Event { Used(K), } // Handles interactions with slots -pub struct SlotManager { - state: ManagerState, +pub struct SlotManager { + state: ManagerState, // Rebuilt every frame slot_ids: Vec, // Rebuilt every frame - slot_kinds: Vec, - events: Vec>, + slots: Vec, + events: Vec>, // Widget id for dragging image drag_id: widget::Id, // Size to display dragged content @@ -125,25 +125,25 @@ pub struct SlotManager { drag_img_size: Vec2, } -impl SlotManager +impl SlotManager where - K: SlotKinds, + S: SumSlot, { pub fn new(mut gen: widget::id::Generator, drag_img_size: Vec2) -> Self { Self { state: ManagerState::Idle, slot_ids: Vec::new(), - slot_kinds: Vec::new(), + slots: Vec::new(), events: Vec::new(), drag_id: gen.next(), drag_img_size, } } - pub fn maintain(&mut self, ui: &mut conrod_core::UiCell) -> Vec> { + pub fn maintain(&mut self, ui: &mut conrod_core::UiCell) -> Vec> { // Clear let slot_ids = std::mem::replace(&mut self.slot_ids, Vec::new()); - let slot_kinds = std::mem::replace(&mut self.slot_kinds, Vec::new()); + let slots = std::mem::replace(&mut self.slots, Vec::new()); // Detect drops by of selected item by clicking in empty space if let ManagerState::Selected(_, slot) = self.state { @@ -166,7 +166,7 @@ where self.events.push(Event::Dropped(*slot)); } else if let Some(idx) = slot_ids.iter().position(|slot_id| *slot_id == id) { // If widget is a slot widget swap with it - self.events.push(Event::Dragged(*slot, slot_kinds[idx])); + self.events.push(Event::Dragged(*slot, slots[idx])); } } // Mouse released stop dragging @@ -187,13 +187,13 @@ where fn update( &mut self, widget: widget::Id, - slot: K, + slot: S, ui: &conrod_core::Ui, content_img: Option, ) -> Interaction { // Add to list of slots self.slot_ids.push(widget); - self.slot_kinds.push(slot); + self.slots.push(slot); let filled = content_img.is_some(); // If the slot is no longer filled deselect it or cancel dragging @@ -280,8 +280,8 @@ where } #[derive(WidgetCommon)] -pub struct Slot<'a, C: ContentKey + Into, K: SlotKinds> { - content: C, +pub struct Slot<'a, K: SlotKey + Into, C, I, S: SumSlot> { + slot_key: K, // Images for slot background and frame empty_slot: image::Id, @@ -301,10 +301,10 @@ pub struct Slot<'a, C: ContentKey + Into, K: SlotKinds> { amount_margins: Vec2, amount_text_color: Color, - slot_manager: Option<&'a mut SlotManager>, + slot_manager: Option<&'a mut SlotManager>, // Should we just pass in the ImageKey? - content_source: &'a C::ContentSource, - image_source: &'a C::ImageSource, + content_source: &'a C, + image_source: &'a I, #[conrod(common_builder)] common: widget::CommonBuilder, @@ -322,29 +322,32 @@ widget_ids! { } /// Represents the state of the Slot widget. -pub struct State { +pub struct State { ids: Ids, cached_image: Option<(K, image::Id)>, - slot_kind: S, } -impl<'a, C, K> Slot<'a, C, K> +impl<'a, K, C, I, S> Slot<'a, K, C, I, S> where - C: ContentKey + Into, - K: SlotKinds, + K: SlotKey + Into, + S: SumSlot, { builder_methods! { - pub with_manager { slot_manager = Some(&'a mut SlotManager) } pub with_background_color { background_color = Some(Color) } } + pub fn with_manager(mut self, slot_manager: &'a mut SlotManager) -> Self { + self.slot_manager = Some(slot_manager); + self + } + pub fn with_icon(mut self, img: image::Id, size: Vec2, color: Option) -> Self { self.icon = Some((img, size, color)); self } fn new( - content: C, + slot_key: K, empty_slot: image::Id, filled_slot: image::Id, selected_slot: image::Id, @@ -354,11 +357,11 @@ where amount_font_size: u32, amount_margins: Vec2, amount_text_color: Color, - content_source: &'a C::ContentSource, - image_source: &'a C::ImageSource, + content_source: &'a C, + image_source: &'a I, ) -> Self { Self { - content, + slot_key, empty_slot, filled_slot, selected_slot, @@ -378,20 +381,19 @@ where } } -impl<'a, C, K> Widget for Slot<'a, C, K> +impl<'a, K, C, I, S> Widget for Slot<'a, K, C, I, S> where - C: ContentKey + Into, - K: SlotKinds, + K: SlotKey + Into, + S: SumSlot, { type Event = (); - type State = State; + type State = State; type Style = (); fn init_state(&self, id_gen: widget::id::Generator) -> Self::State { State { ids: Ids::new(id_gen), cached_image: None, - slot_kind: self.content.into(), } } @@ -407,7 +409,7 @@ where .. } = args; let Slot { - content, + slot_key, empty_slot, filled_slot, selected_slot, @@ -425,29 +427,21 @@ where } = self; // If the key changed update the cached image id - let image_key = content.image_key(content_source); + let image_key = slot_key.image_key(content_source); if state.cached_image.as_ref().map(|c| &c.0) != image_key.as_ref() { state.update(|state| { state.cached_image = image_key.map(|key| { - let image_id = C::image_id(&key, &image_source); + let image_id = K::image_id(&key, &image_source); (key, image_id) }); }); } - // If the slot kind value changed update the state - let slot_kind = content.into(); - if slot_kind != state.slot_kind { - state.update(|state| { - state.slot_kind = slot_kind; - }); - } - // Get image ids let content_image = state.cached_image.as_ref().map(|c| c.1); // Get whether this slot is selected let interaction = self.slot_manager.map_or(Interaction::None, |m| { - m.update(id, content.into(), ui, content_image) + m.update(id, slot_key.into(), ui, content_image) }); // No content if it is being dragged let content_image = if let Interaction::Dragging = interaction { @@ -465,7 +459,7 @@ where }; // Get amount (None => no amount text) - let amount = content.amount(content_source); + let amount = slot_key.amount(content_source); // Get slot widget dimensions and position let (x, y, w, h) = rect.x_y_w_h();