mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement stacking and splitting
This commit is contained in:
parent
e114786fdb
commit
c0573cca44
@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Talk animation
|
||||
- New bosses in 5 lower dungeons
|
||||
= New enemies in 5 lower dungeons
|
||||
- Item stacking and splitting
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -668,6 +668,30 @@ impl Client {
|
||||
|
||||
pub fn is_dead(&self) -> bool { self.current::<comp::Health>().map_or(false, |h| h.is_dead) }
|
||||
|
||||
pub fn split_swap_slots(&mut self, a: comp::slot::Slot, b: comp::slot::Slot) {
|
||||
match (a, b) {
|
||||
(Slot::Equip(equip), slot) | (slot, Slot::Equip(equip)) => {
|
||||
self.control_action(ControlAction::LoadoutManip(LoadoutManip::Swap(equip, slot)))
|
||||
},
|
||||
(Slot::Inventory(inv1), Slot::Inventory(inv2)) => {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::SplitSwap(inv1, inv2),
|
||||
)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_drop_slot(&mut self, slot: comp::slot::Slot) {
|
||||
match slot {
|
||||
Slot::Equip(equip) => {
|
||||
self.control_action(ControlAction::LoadoutManip(LoadoutManip::Drop(equip)))
|
||||
},
|
||||
Slot::Inventory(inv) => self.send_msg(ClientGeneral::ControlEvent(
|
||||
ControlEvent::InventoryManip(InventoryManip::SplitDrop(inv)),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pick_up(&mut self, entity: EcsEntity) {
|
||||
// Get the health component from the entity
|
||||
|
||||
|
@ -23,7 +23,9 @@ pub enum InventoryManip {
|
||||
Collect(Vec3<i32>),
|
||||
Use(InvSlotId),
|
||||
Swap(InvSlotId, InvSlotId),
|
||||
SplitSwap(InvSlotId, InvSlotId),
|
||||
Drop(InvSlotId),
|
||||
SplitDrop(InvSlotId),
|
||||
CraftRecipe(String),
|
||||
}
|
||||
|
||||
@ -40,7 +42,9 @@ pub enum SlotManip {
|
||||
Collect(Vec3<i32>),
|
||||
Use(Slot),
|
||||
Swap(Slot, Slot),
|
||||
SplitSwap(Slot, Slot),
|
||||
Drop(Slot),
|
||||
SplitDrop(Slot),
|
||||
CraftRecipe(String),
|
||||
}
|
||||
|
||||
@ -63,7 +67,11 @@ impl From<InventoryManip> for SlotManip {
|
||||
InventoryManip::Swap(inv1, inv2) => {
|
||||
Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
|
||||
},
|
||||
InventoryManip::SplitSwap(inv1, inv2) => {
|
||||
Self::SplitSwap(Slot::Inventory(inv1), Slot::Inventory(inv2))
|
||||
},
|
||||
InventoryManip::Drop(inv) => Self::Drop(Slot::Inventory(inv)),
|
||||
InventoryManip::SplitDrop(inv) => Self::SplitDrop(Slot::Inventory(inv)),
|
||||
InventoryManip::CraftRecipe(recipe) => Self::CraftRecipe(recipe),
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +167,32 @@ impl Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge the stack of items at src into the stack at dst if the items are
|
||||
/// compatible and stackable, and return whether anything was changed
|
||||
pub fn merge_stack_into(&mut self, src: InvSlotId, dst: InvSlotId) -> bool {
|
||||
let mut amount = None;
|
||||
if let (Some(srcitem), Some(dstitem)) = (self.get(src), self.get(dst)) {
|
||||
// The equality check ensures the items have the same definition, to avoid e.g.
|
||||
// transmuting coins to diamonds, and the stackable check avoids creating a
|
||||
// stack of swords
|
||||
if srcitem == dstitem && srcitem.is_stackable() {
|
||||
amount = Some(srcitem.amount());
|
||||
}
|
||||
}
|
||||
if let Some(amount) = amount {
|
||||
self.remove(src);
|
||||
let dstitem = self
|
||||
.get_mut(dst)
|
||||
.expect("self.get(dst) was Some right above this");
|
||||
dstitem
|
||||
.increase_amount(amount)
|
||||
.expect("already checked is_stackable");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if inserting item exists in given cell. Inserts an item if it
|
||||
/// exists.
|
||||
pub fn insert_or_stack_at(
|
||||
@ -215,6 +241,11 @@ impl Inventory {
|
||||
self.slot(inv_slot_id).and_then(Option::as_ref)
|
||||
}
|
||||
|
||||
/// Mutably get content of a slot
|
||||
fn get_mut(&mut self, inv_slot_id: InvSlotId) -> Option<&mut Item> {
|
||||
self.slot_mut(inv_slot_id).and_then(Option::as_mut)
|
||||
}
|
||||
|
||||
/// Returns a reference to the item (if any) equipped in the given EquipSlot
|
||||
pub fn equipped(&self, equip_slot: EquipSlot) -> Option<&Item> {
|
||||
self.loadout.equipped(equip_slot)
|
||||
@ -275,6 +306,29 @@ impl Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes half of the items from a slot in the inventory
|
||||
pub fn take_half(
|
||||
&mut self,
|
||||
inv_slot_id: InvSlotId,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> Option<Item> {
|
||||
if let Some(Some(item)) = self.slot_mut(inv_slot_id) {
|
||||
if item.is_stackable() && item.amount() > 1 {
|
||||
let mut return_item = item.duplicate(msm);
|
||||
let returning_amount = item.amount() / 2;
|
||||
item.decrease_amount(returning_amount).ok()?;
|
||||
return_item
|
||||
.set_amount(returning_amount)
|
||||
.expect("Items duplicated from a stackable item must be stackable.");
|
||||
Some(return_item)
|
||||
} else {
|
||||
self.remove(inv_slot_id)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes all items from the inventory
|
||||
pub fn drain(&mut self) -> impl Iterator<Item = Item> + '_ {
|
||||
self.slots_mut()
|
||||
|
@ -5,7 +5,8 @@ use vek::{Rgb, Vec3};
|
||||
|
||||
use common::{
|
||||
comp::{
|
||||
self, item,
|
||||
self,
|
||||
item::{self, MaterialStatManifest},
|
||||
slot::{self, Slot},
|
||||
},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
@ -429,6 +430,16 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Slo
|
||||
if let Some(pos) = ecs.read_storage::<comp::Pos>().get(entity) {
|
||||
if let Some(mut inventory) = ecs.write_storage::<comp::Inventory>().get_mut(entity)
|
||||
{
|
||||
let mut merged_stacks = false;
|
||||
|
||||
// If both slots have items and we're attemping to drag from one stack
|
||||
// into another, stack the items.
|
||||
if let (Slot::Inventory(slot_a), Slot::Inventory(slot_b)) = (a, b) {
|
||||
merged_stacks |= inventory.merge_stack_into(slot_a, slot_b);
|
||||
}
|
||||
|
||||
// If the stacks weren't mergable carry out a swap.
|
||||
if !merged_stacks {
|
||||
dropped_items.extend(inventory.swap(a, b).into_iter().map(|x| {
|
||||
(
|
||||
*pos,
|
||||
@ -440,6 +451,56 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Slo
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.write_component(
|
||||
entity,
|
||||
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Swapped),
|
||||
);
|
||||
},
|
||||
|
||||
comp::SlotManip::SplitSwap(slot, target) => {
|
||||
let msm = state.ecs().read_resource::<MaterialStatManifest>();
|
||||
let mut inventories = state.ecs().write_storage::<comp::Inventory>();
|
||||
let mut inventory = if let Some(inventory) = inventories.get_mut(entity) {
|
||||
inventory
|
||||
} else {
|
||||
error!(
|
||||
?entity,
|
||||
"Can't manipulate inventory, entity doesn't have one"
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
// If both slots have items and we're attemping to split from one stack
|
||||
// into another, ensure that they are the same type of item. If they are
|
||||
// the same type do nothing, as you don't want to overwrite the existing item.
|
||||
|
||||
if let (Slot::Inventory(source_inv_slot_id), Slot::Inventory(target_inv_slot_id)) =
|
||||
(slot, target)
|
||||
{
|
||||
if let Some(source_item) = inventory.get(source_inv_slot_id) {
|
||||
if let Some(target_item) = inventory.get(target_inv_slot_id) {
|
||||
if source_item != target_item {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let item = match slot {
|
||||
Slot::Inventory(slot) => inventory.take_half(slot, &msm),
|
||||
Slot::Equip(_) => None,
|
||||
};
|
||||
|
||||
if let Some(item) = item {
|
||||
if let Slot::Inventory(target) = target {
|
||||
inventory.insert_or_stack_at(target, item).ok();
|
||||
}
|
||||
}
|
||||
drop(inventory);
|
||||
drop(inventories);
|
||||
drop(msm);
|
||||
|
||||
state.write_component(
|
||||
entity,
|
||||
@ -480,6 +541,37 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Slo
|
||||
);
|
||||
},
|
||||
|
||||
comp::SlotManip::SplitDrop(slot) => {
|
||||
let msm = state.ecs().read_resource::<MaterialStatManifest>();
|
||||
let item = match slot {
|
||||
Slot::Inventory(slot) => state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.and_then(|mut inv| inv.take_half(slot, &msm)),
|
||||
Slot::Equip(_) => None,
|
||||
};
|
||||
|
||||
// FIXME: We should really require the drop and write to be atomic!
|
||||
if let (Some(mut item), Some(pos)) =
|
||||
(item, state.ecs().read_storage::<comp::Pos>().get(entity))
|
||||
{
|
||||
item.put_in_world();
|
||||
dropped_items.push((
|
||||
*pos,
|
||||
state
|
||||
.read_component_copied::<comp::Ori>(entity)
|
||||
.unwrap_or_default(),
|
||||
item,
|
||||
));
|
||||
}
|
||||
drop(msm);
|
||||
state.write_component(
|
||||
entity,
|
||||
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Dropped),
|
||||
);
|
||||
},
|
||||
|
||||
comp::SlotManip::CraftRecipe(recipe) => {
|
||||
if let Some(mut inv) = state
|
||||
.ecs()
|
||||
|
@ -391,7 +391,13 @@ pub enum Event {
|
||||
slot_b: comp::slot::Slot,
|
||||
bypass_dialog: bool,
|
||||
},
|
||||
SplitSwapSlots {
|
||||
slot_a: comp::slot::Slot,
|
||||
slot_b: comp::slot::Slot,
|
||||
bypass_dialog: bool,
|
||||
},
|
||||
DropSlot(comp::slot::Slot),
|
||||
SplitDropSlot(comp::slot::Slot),
|
||||
ChangeHotbarState(Box<HotbarState>),
|
||||
TradeAction(TradeAction),
|
||||
Ability3(bool),
|
||||
@ -769,7 +775,15 @@ impl Hud {
|
||||
let hotbar_state =
|
||||
HotbarState::new(global_state.profile.get_hotbar_slots(server, character_id));
|
||||
|
||||
let slot_manager = slots::SlotManager::new(ui.id_generator(), Vec2::broadcast(40.0));
|
||||
let slot_manager = slots::SlotManager::new(
|
||||
ui.id_generator(),
|
||||
Vec2::broadcast(40.0)
|
||||
// TODO(heyzoos) Will be useful for whoever works on rendering the number of items "in hand".
|
||||
// fonts.cyri.conrod_id,
|
||||
// Vec2::new(1.0, 1.0),
|
||||
// fonts.cyri.scale(12),
|
||||
// TEXT_COLOR,
|
||||
);
|
||||
|
||||
Self {
|
||||
ui,
|
||||
@ -2788,6 +2802,31 @@ impl Hud {
|
||||
}
|
||||
}
|
||||
},
|
||||
slot::Event::SplitDropped(from) => {
|
||||
// Drop item
|
||||
if let Some(from) = to_slot(from) {
|
||||
events.push(Event::SplitDropSlot(from));
|
||||
} else if let Hotbar(h) = from {
|
||||
self.hotbar.clear_slot(h);
|
||||
events.push(Event::ChangeHotbarState(Box::new(self.hotbar.to_owned())));
|
||||
}
|
||||
},
|
||||
slot::Event::SplitDragged(a, b) => {
|
||||
// Swap between slots
|
||||
if let (Some(a), Some(b)) = (to_slot(a), to_slot(b)) {
|
||||
events.push(Event::SplitSwapSlots {
|
||||
slot_a: a,
|
||||
slot_b: b,
|
||||
bypass_dialog: false,
|
||||
});
|
||||
} else if let (Inventory(i), Hotbar(h)) = (a, b) {
|
||||
self.hotbar.add_inventory_link(h, i.slot);
|
||||
events.push(Event::ChangeHotbarState(Box::new(self.hotbar.to_owned())));
|
||||
} else if let (Hotbar(a), Hotbar(b)) = (a, b) {
|
||||
self.hotbar.swap(a, b);
|
||||
events.push(Event::ChangeHotbarState(Box::new(self.hotbar.to_owned())));
|
||||
}
|
||||
},
|
||||
slot::Event::Used(from) => {
|
||||
// Item used (selected and then clicked again)
|
||||
if let Some(from) = to_slot(from) {
|
||||
|
@ -1136,6 +1136,57 @@ impl PlayState for SessionState {
|
||||
self.client.borrow_mut().swap_slots(slot_a, slot_b);
|
||||
}
|
||||
},
|
||||
HudEvent::SplitSwapSlots {
|
||||
slot_a,
|
||||
slot_b,
|
||||
bypass_dialog,
|
||||
} => {
|
||||
let mut move_allowed = true;
|
||||
if !bypass_dialog {
|
||||
if let Some(inventory) = self
|
||||
.client
|
||||
.borrow()
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::Inventory>()
|
||||
.get(self.client.borrow().entity())
|
||||
{
|
||||
match (slot_a, slot_b) {
|
||||
(Slot::Inventory(inv_slot), Slot::Equip(equip_slot))
|
||||
| (Slot::Equip(equip_slot), Slot::Inventory(inv_slot)) => {
|
||||
if !inventory.can_swap(inv_slot, equip_slot) {
|
||||
move_allowed = false;
|
||||
} else {
|
||||
let slot_deficit =
|
||||
inventory.free_after_swap(equip_slot, inv_slot);
|
||||
if slot_deficit < 0 {
|
||||
self.hud.set_prompt_dialog(
|
||||
PromptDialogSettings::new(
|
||||
format!(
|
||||
"This will result in dropping {} \
|
||||
item(s) on the ground. Are you sure?",
|
||||
slot_deficit.abs()
|
||||
),
|
||||
HudEvent::SwapSlots {
|
||||
slot_a,
|
||||
slot_b,
|
||||
bypass_dialog: true,
|
||||
},
|
||||
None,
|
||||
),
|
||||
);
|
||||
move_allowed = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
};
|
||||
if move_allowed {
|
||||
self.client.borrow_mut().split_swap_slots(slot_a, slot_b);
|
||||
}
|
||||
},
|
||||
HudEvent::DropSlot(x) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.drop_slot(x);
|
||||
@ -1143,6 +1194,13 @@ impl PlayState for SessionState {
|
||||
client.disable_lantern();
|
||||
}
|
||||
},
|
||||
HudEvent::SplitDropSlot(x) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.split_drop_slot(x);
|
||||
if let comp::slot::Slot::Equip(comp::slot::EquipSlot::Lantern) = x {
|
||||
client.disable_lantern();
|
||||
}
|
||||
},
|
||||
HudEvent::ChangeHotbarState(state) => {
|
||||
let client = self.client.borrow();
|
||||
|
||||
|
@ -94,7 +94,13 @@ where
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ManagerState<K> {
|
||||
Dragging(widget::Id, K, image::Id),
|
||||
Dragging(
|
||||
widget::Id,
|
||||
K,
|
||||
image::Id,
|
||||
/// Amount of items being dragged in the stack.
|
||||
Option<u32>,
|
||||
),
|
||||
Selected(widget::Id, K),
|
||||
Idle,
|
||||
}
|
||||
@ -110,6 +116,10 @@ pub enum Event<K> {
|
||||
Dragged(K, K),
|
||||
// Dragged to open space
|
||||
Dropped(K),
|
||||
// Dropped half of the stack
|
||||
SplitDropped(K),
|
||||
// Dragged half of the stack
|
||||
SplitDragged(K, K),
|
||||
// Clicked while selected
|
||||
Used(K),
|
||||
}
|
||||
@ -127,21 +137,56 @@ pub struct SlotManager<S: SumSlot> {
|
||||
// Note: could potentially be specialized for each slot if needed
|
||||
drag_img_size: Vec2<f32>,
|
||||
pub mouse_over_slot: Option<S>,
|
||||
/* TODO(heyzoos) Will be useful for whoever works on rendering the number of items "in
|
||||
* hand".
|
||||
*
|
||||
* drag_amount_id: widget::Id,
|
||||
* drag_amount_shadow_id: widget::Id, */
|
||||
|
||||
/* Asset ID pointing to a font set.
|
||||
* amount_font: font::Id, */
|
||||
|
||||
/* Specifies the size of the font used to display number of items held in
|
||||
* a stack when dragging.
|
||||
* amount_font_size: u32, */
|
||||
|
||||
/* Specifies how much space should be used in the margins of the item
|
||||
* amount relative to the slot.
|
||||
* amount_margins: Vec2<f32>, */
|
||||
|
||||
/* Specifies the color of the text used to display the number of items held
|
||||
* in a stack when dragging.
|
||||
* amount_text_color: Color, */
|
||||
}
|
||||
|
||||
impl<S> SlotManager<S>
|
||||
where
|
||||
S: SumSlot,
|
||||
{
|
||||
pub fn new(mut gen: widget::id::Generator, drag_img_size: Vec2<f32>) -> Self {
|
||||
pub fn new(
|
||||
mut gen: widget::id::Generator,
|
||||
drag_img_size: Vec2<f32>,
|
||||
/* TODO(heyzoos) Will be useful for whoever works on rendering the number of items "in
|
||||
* hand". amount_font: font::Id,
|
||||
* amount_margins: Vec2<f32>,
|
||||
* amount_font_size: u32,
|
||||
* amount_text_color: Color, */
|
||||
) -> Self {
|
||||
Self {
|
||||
state: ManagerState::Idle,
|
||||
slot_ids: Vec::new(),
|
||||
slots: Vec::new(),
|
||||
events: Vec::new(),
|
||||
drag_id: gen.next(),
|
||||
drag_img_size,
|
||||
mouse_over_slot: None,
|
||||
// TODO(heyzoos) Will be useful for whoever works on rendering the number of items "in
|
||||
// hand". drag_amount_id: gen.next(),
|
||||
// drag_amount_shadow_id: gen.next(),
|
||||
// amount_font,
|
||||
// amount_font_size,
|
||||
// amount_margins,
|
||||
// amount_text_color,
|
||||
drag_img_size,
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,8 +211,32 @@ where
|
||||
|
||||
// If dragging and mouse is released check if there is a slot widget under the
|
||||
// mouse
|
||||
if let ManagerState::Dragging(_, slot, content_img) = &self.state {
|
||||
if let ManagerState::Dragging(_, slot, content_img, drag_amount) = &self.state {
|
||||
let content_img = *content_img;
|
||||
let drag_amount = *drag_amount;
|
||||
|
||||
// If we are dragging and we right click, drop half the stack
|
||||
// on the ground or into the slot under the cursor. This only
|
||||
// works with open slots or slots containing the same kind of
|
||||
// item.
|
||||
|
||||
if drag_amount.is_some() {
|
||||
if let Some(id) = input.widget_under_mouse {
|
||||
if ui.widget_input(id).clicks().right().next().is_some() {
|
||||
if id == ui.window {
|
||||
let temp_slot = *slot;
|
||||
self.events.push(Event::SplitDropped(temp_slot));
|
||||
} else if let Some(idx) = slot_ids.iter().position(|slot_id| *slot_id == id)
|
||||
{
|
||||
let (from, to) = (*slot, slots[idx]);
|
||||
if from != to {
|
||||
self.events.push(Event::SplitDragged(from, to));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let mouse::ButtonPosition::Up = input.mouse.buttons.left() {
|
||||
// Get widget under the mouse
|
||||
if let Some(id) = input.widget_under_mouse {
|
||||
@ -186,6 +255,7 @@ where
|
||||
// Mouse released stop dragging
|
||||
self.state = ManagerState::Idle;
|
||||
}
|
||||
|
||||
// Draw image of contents being dragged
|
||||
let [mouse_x, mouse_y] = input.mouse.xy;
|
||||
let size = self.drag_img_size.map(|e| e as f64).into_array();
|
||||
@ -193,6 +263,34 @@ where
|
||||
.wh(size)
|
||||
.xy([mouse_x, mouse_y])
|
||||
.set(self.drag_id, ui);
|
||||
|
||||
// TODO(heyzoos) Will be useful for whoever works on rendering the
|
||||
// number of items "in hand".
|
||||
//
|
||||
// if let Some(drag_amount) = drag_amount {
|
||||
// Text::new(format!("{}", drag_amount).as_str())
|
||||
// .parent(self.drag_id)
|
||||
// .font_id(self.amount_font)
|
||||
// .font_size(self.amount_font_size)
|
||||
// .bottom_right_with_margins_on(
|
||||
// self.drag_id,
|
||||
// self.amount_margins.x as f64,
|
||||
// self.amount_margins.y as f64,
|
||||
// )
|
||||
// .color(Color::Rgba(0.0, 0.0, 0.0, 1.0))
|
||||
// .set(self.drag_amount_shadow_id, ui);
|
||||
// Text::new(format!("{}", drag_amount).as_str())
|
||||
// .parent(self.drag_id)
|
||||
// .font_id(self.amount_font)
|
||||
// .font_size(self.amount_font_size)
|
||||
// .bottom_right_with_margins_on(
|
||||
// self.drag_id,
|
||||
// self.amount_margins.x as f64,
|
||||
// self.amount_margins.y as f64,
|
||||
// )
|
||||
// .color(self.amount_text_color)
|
||||
// .set(self.drag_amount_id, ui);
|
||||
// }
|
||||
}
|
||||
|
||||
std::mem::replace(&mut self.events, Vec::new())
|
||||
@ -204,6 +302,7 @@ where
|
||||
slot: S,
|
||||
ui: &conrod_core::Ui,
|
||||
content_img: Option<Vec<image::Id>>,
|
||||
drag_amount: Option<u32>,
|
||||
) -> Interaction {
|
||||
// Add to list of slots
|
||||
self.slot_ids.push(widget);
|
||||
@ -212,7 +311,7 @@ where
|
||||
let filled = content_img.is_some();
|
||||
// If the slot is no longer filled deselect it or cancel dragging
|
||||
match &self.state {
|
||||
ManagerState::Selected(id, _) | ManagerState::Dragging(id, _, _)
|
||||
ManagerState::Selected(id, _) | ManagerState::Dragging(id, _, _, _)
|
||||
if *id == widget && !filled =>
|
||||
{
|
||||
self.state = ManagerState::Idle;
|
||||
@ -223,7 +322,7 @@ where
|
||||
// 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, _)
|
||||
| ManagerState::Dragging(id, stored_slot, _, _)
|
||||
if *id == widget =>
|
||||
{
|
||||
*stored_slot = slot
|
||||
@ -278,24 +377,26 @@ where
|
||||
// If something is selected, deselect
|
||||
self.state = ManagerState::Idle;
|
||||
},
|
||||
ManagerState::Dragging(_, _, _) => {},
|
||||
ManagerState::Dragging(_, _, _, _) => {},
|
||||
}
|
||||
}
|
||||
|
||||
// If not dragging and there is a drag event on this slot start dragging
|
||||
if input.drags().left().next().is_some()
|
||||
&& !matches!(self.state, ManagerState::Dragging(_, _, _))
|
||||
&& !matches!(self.state, ManagerState::Dragging(_, _, _, _))
|
||||
{
|
||||
// Start dragging if widget is filled
|
||||
if let Some(img) = content_img {
|
||||
self.state = ManagerState::Dragging(widget, slot, img[0]);
|
||||
if let Some(images) = content_img {
|
||||
if !images.is_empty() {
|
||||
self.state = ManagerState::Dragging(widget, slot, images[0], drag_amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether this slot is being interacted with
|
||||
match self.state {
|
||||
ManagerState::Selected(id, _) if id == widget => Interaction::Selected,
|
||||
ManagerState::Dragging(id, _, _) if id == widget => Interaction::Dragging,
|
||||
ManagerState::Dragging(id, _, _, _) if id == widget => Interaction::Dragging,
|
||||
_ => Interaction::None,
|
||||
}
|
||||
}
|
||||
@ -488,7 +589,13 @@ where
|
||||
let content_images = state.cached_images.as_ref().map(|c| c.1.clone());
|
||||
// Get whether this slot is selected
|
||||
let interaction = self.slot_manager.map_or(Interaction::None, |m| {
|
||||
m.update(id, slot_key.into(), ui, content_images.clone())
|
||||
m.update(
|
||||
id,
|
||||
slot_key.into(),
|
||||
ui,
|
||||
content_images.clone(),
|
||||
slot_key.amount(content_source),
|
||||
)
|
||||
});
|
||||
// No content if it is being dragged
|
||||
let content_images = if let Interaction::Dragging = interaction {
|
||||
|
Loading…
Reference in New Issue
Block a user