return ItemSpec(InventoryLocation(), "", -1);
}
-void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
+void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int layer,
bool &item_hovered)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
- for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
- {
+ for (s32 i = 0; i < s.geom.X * s.geom.Y; i++) {
s32 item_i = i + s.start_item_i;
- if(item_i >= (s32) ilist->getSize())
+ if (item_i >= (s32)ilist->getSize())
break;
+
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
- ItemStack item;
- if(ilist)
- item = ilist->getItem(item_i);
+ ItemStack item = ilist->getItem(item_i);
bool selected = m_selected_item
&& m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
ItemRotationKind rotation_kind = selected ? IT_ROT_SELECTED :
(hovering ? IT_ROT_HOVERED : IT_ROT_NONE);
- if (phase == 0) {
+ if (layer == 0) {
if (hovering) {
item_hovered = true;
driver->draw2DRectangle(m_slotbg_h, rect, &AbsoluteClippingRect);
v2s32(x2 + border, y2)), NULL);
}
- if(phase == 1)
- {
+ if (layer == 1) {
// Draw item stack
- if(selected)
- {
+ if (selected)
item.takeItem(m_selected_amount);
- }
- if(!item.empty())
- {
+
+ if (!item.empty()) {
drawItemStack(driver, m_font, item,
rect, &AbsoluteClippingRect, m_client,
rotation_kind);
/*
Draw items
- Phase 0: Item slot rectangles
- Phase 1: Item images; prepare tooltip
+ Layer 0: Item slot rectangles
+ Layer 1: Item images; prepare tooltip
*/
bool item_hovered = false;
- int start_phase = 0;
- for (int phase = start_phase; phase <= 1; phase++) {
+ for (int layer = 0; layer < 2; layer++) {
for (const GUIFormSpecMenu::ListDrawSpec &spec : m_inventorylists) {
- drawList(spec, phase, item_hovered);
+ drawList(spec, layer, item_hovered);
}
}
if (!item_hovered) {
void GUIFormSpecMenu::updateSelectedItem()
{
- // If the selected stack has become empty for some reason, deselect it.
- // If the selected stack has become inaccessible, deselect it.
- // If the selected stack has become smaller, adjust m_selected_amount.
- ItemStack selected = verifySelectedItem();
-
- // WARNING: BLACK MAGIC
- // See if there is a stack suited for our current guess.
- // If such stack does not exist, clear the guess.
- if (!m_selected_content_guess.name.empty() &&
- selected.name == m_selected_content_guess.name &&
- selected.count == m_selected_content_guess.count){
- // Selected item fits the guess. Skip the black magic.
- } else if (!m_selected_content_guess.name.empty()) {
- bool found = false;
- for(u32 i=0; i<m_inventorylists.size() && !found; i++){
- const ListDrawSpec &s = m_inventorylists[i];
+ verifySelectedItem();
+
+ // If craftresult is nonempty and nothing else is selected, select it now.
+ if (!m_selected_item) {
+ for (const GUIFormSpecMenu::ListDrawSpec &s : m_inventorylists) {
+ if (s.listname != "craftpreview")
+ continue;
+
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
- if(!inv)
+ if (!inv)
continue;
- InventoryList *list = inv->getList(s.listname);
- if(!list)
+
+ InventoryList *list = inv->getList("craftresult");
+
+ if (!list || list->getSize() == 0)
continue;
- for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){
- u32 item_i = i + s.start_item_i;
- if(item_i >= list->getSize())
- continue;
- ItemStack stack = list->getItem(item_i);
- if(stack.name == m_selected_content_guess.name &&
- stack.count == m_selected_content_guess.count){
- found = true;
- infostream<<"Client: Changing selected content guess to "
- <<s.inventoryloc.dump()<<" "<<s.listname
- <<" "<<item_i<<std::endl;
- delete m_selected_item;
- m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i);
- m_selected_amount = stack.count;
- }
- }
- }
- if(!found){
- infostream<<"Client: Discarding selected content guess: "
- <<m_selected_content_guess.getItemString()<<std::endl;
- m_selected_content_guess.name = "";
- }
- }
- // If craftresult is nonempty and nothing else is selected, select it now.
- if(!m_selected_item)
- {
- for (const GUIFormSpecMenu::ListDrawSpec &s : m_inventorylists) {
- if(s.listname == "craftpreview")
- {
- Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
- InventoryList *list = inv->getList("craftresult");
- if(list && list->getSize() >= 1 && !list->getItem(0).empty())
- {
- m_selected_item = new ItemSpec;
- m_selected_item->inventoryloc = s.inventoryloc;
- m_selected_item->listname = "craftresult";
- m_selected_item->i = 0;
- m_selected_amount = 0;
- m_selected_dragging = false;
- break;
- }
- }
+ const ItemStack &item = list->getItem(0);
+ if (item.empty())
+ continue;
+
+ // Grab selected item from the crafting result list
+ m_selected_item = new ItemSpec;
+ m_selected_item->inventoryloc = s.inventoryloc;
+ m_selected_item->listname = "craftresult";
+ m_selected_item->i = 0;
+ m_selected_amount = item.count;
+ m_selected_dragging = false;
+ break;
}
}
// If craftresult is selected, keep the whole stack selected
- if(m_selected_item && m_selected_item->listname == "craftresult")
- {
+ if (m_selected_item && m_selected_item->listname == "craftresult")
m_selected_amount = verifySelectedItem().count;
- }
}
ItemStack GUIFormSpecMenu::verifySelectedItem()
if(list && (u32) m_selected_item->i < list->getSize())
{
ItemStack stack = list->getItem(m_selected_item->i);
- if(m_selected_amount > stack.count)
- m_selected_amount = stack.count;
- if(!stack.empty())
+ if (!m_selected_swap.empty()) {
+ if (m_selected_swap.name == stack.name &&
+ m_selected_swap.count == stack.count)
+ m_selected_swap.clear();
+ } else {
+ m_selected_amount = std::min(m_selected_amount, stack.count);
+ }
+
+ if (!stack.empty())
return stack;
}
}
}
}
+enum ButtonEventType : u8
+{
+ BET_LEFT,
+ BET_RIGHT,
+ BET_MIDDLE,
+ BET_WHEEL_UP,
+ BET_WHEEL_DOWN,
+ BET_UP,
+ BET_DOWN,
+ BET_MOVE,
+ BET_OTHER
+};
+
bool GUIFormSpecMenu::OnEvent(const SEvent& event)
{
if (event.EventType==EET_KEY_INPUT_EVENT) {
s_count = list_s->getItem(s.i).count;
} while(0);
- bool identical = (m_selected_item != NULL) && s.isValid() &&
+ bool identical = m_selected_item && s.isValid() &&
(inv_selected == inv_s) &&
(m_selected_item->listname == s.listname) &&
(m_selected_item->i == s.i);
- // buttons: 0 = left, 1 = right, 2 = middle, 3 = wheeldown, 4 = wheelup
- // up/down: 0 = down (press or wheel), 1 = up (release),
- // 2 = unknown event, -1 = movement
- int button = 0;
- int updown = 2;
+ ButtonEventType button = BET_LEFT;
+ ButtonEventType updown = BET_OTHER;
switch (event.MouseInput.Event) {
case EMIE_LMOUSE_PRESSED_DOWN:
- button = 0; updown = 0;
+ button = BET_LEFT; updown = BET_DOWN;
break;
case EMIE_RMOUSE_PRESSED_DOWN:
- button = 1; updown = 0;
+ button = BET_RIGHT; updown = BET_DOWN;
break;
case EMIE_MMOUSE_PRESSED_DOWN:
- button = 2; updown = 0;
+ button = BET_MIDDLE; updown = BET_DOWN;
break;
case EMIE_MOUSE_WHEEL:
- button = 3 + (event.MouseInput.Wheel > 0); updown = 0;
+ button = (event.MouseInput.Wheel > 0) ?
+ BET_WHEEL_UP : BET_WHEEL_DOWN;
+ updown = BET_DOWN;
break;
case EMIE_LMOUSE_LEFT_UP:
- button = 0; updown = 1;
+ button = BET_LEFT; updown = BET_UP;
break;
case EMIE_RMOUSE_LEFT_UP:
- button = 1; updown = 1;
+ button = BET_RIGHT; updown = BET_UP;
break;
case EMIE_MMOUSE_LEFT_UP:
- button = 2; updown = 1;
+ button = BET_MIDDLE; updown = BET_UP;
break;
case EMIE_MOUSE_MOVED:
- updown = -1;
+ updown = BET_MOVE;
break;
default:
break;
// Set this number to a positive value to generate a craft action at s.
u32 craft_amount = 0;
- if (!updown) {
+ switch (updown) {
+ case BET_DOWN:
// Some mouse button has been pressed
//infostream<<"Mouse button "<<button<<" pressed at p=("
if (s.isValid() && s.listname == "craftpreview") {
// Craft preview has been clicked: craft
- craft_amount = (button == 2 ? 10 : 1);
- } else if (m_selected_item == NULL) {
- if (s_count && button != 4) {
+ craft_amount = (button == BET_MIDDLE ? 10 : 1);
+ } else if (!m_selected_item) {
+ if (s_count && button != BET_WHEEL_UP) {
// Non-empty stack has been clicked: select or shift-move it
m_selected_item = new ItemSpec(s);
u32 count;
- if (button == 1) // right
+ if (button == BET_RIGHT)
count = (s_count + 1) / 2;
- else if (button == 2) // middle
+ else if (button == BET_MIDDLE)
count = MYMIN(s_count, 10);
- else if (button == 3) // wheeldown
+ else if (button == BET_WHEEL_DOWN)
count = 1;
else // left
count = s_count;
if (!event.MouseInput.Shift) {
// no shift: select item
m_selected_amount = count;
- m_selected_dragging = button != 3;
+ m_selected_dragging = button != BET_WHEEL_DOWN;
m_auto_place = false;
} else {
// shift pressed: move item, right click moves 1
- shift_move_amount = button == 1 ? 1 : count;
+ shift_move_amount = button == BET_RIGHT ? 1 : count;
}
}
} else { // m_selected_item != NULL
if (s.isValid()) {
// Clicked a slot: move
- if (button == 1 || button == 4) // right or wheelup
+ if (button == BET_RIGHT || button == BET_WHEEL_UP)
move_amount = 1;
- else if (button == 2) // middle
+ else if (button == BET_MIDDLE)
move_amount = MYMIN(m_selected_amount, 10);
- else if (!button) // left
+ else if (button == BET_LEFT)
move_amount = m_selected_amount;
// else wheeldown
if (identical) {
- if (button == 3) { // wheeldown
+ if (button == BET_WHEEL_DOWN) {
if (m_selected_amount < s_count)
++m_selected_amount;
} else {
move_amount = 0;
}
}
- }
- else if (!getAbsoluteClippingRect().isPointInside(m_pointer)
- && button != 3) {
+ } else if (!getAbsoluteClippingRect().isPointInside(m_pointer)
+ && button != BET_WHEEL_DOWN) {
// Clicked outside of the window: drop
- if (button == 1 || button == 4) // right or wheelup
+ if (button == BET_RIGHT || button == BET_WHEEL_UP)
drop_amount = 1;
- else if (button == 2) // middle
+ else if (button == BET_MIDDLE)
drop_amount = MYMIN(m_selected_amount, 10);
else // left
drop_amount = m_selected_amount;
}
}
- } else if (updown == 1) {
+ break;
+ case BET_UP:
// Some mouse button has been released
//infostream<<"Mouse button "<<button<<" released at p=("
// <<p.X<<","<<p.Y<<")"<<std::endl;
- if (m_selected_dragging && m_selected_item != NULL) {
+ if (m_selected_dragging && m_selected_item) {
if (s.isValid()) {
if (!identical) {
// Dragged to different slot: move all selected
// + click changes to drop item when moved mode
if (m_selected_item)
m_auto_place = true;
- } else if (updown == -1) {
+ break;
+ case BET_MOVE:
// Mouse has been moved and rmb is down and mouse pointer just
// entered a new inventory field (checked in the entry-if, this
// is the only action here that is generated by mouse movement)
- if (m_selected_item != NULL && s.isValid()) {
+ if (m_selected_item && s.isValid()) {
// Move 1 item
// TODO: middle mouse to move 10 items might be handy
if (m_auto_place) {
move_amount = 1;
}
}
+ break;
+ default:
+ break;
}
// Possibly send inventory action to server
// Check how many items can be moved
move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
ItemStack leftover = stack_to.addItem(stack_from, m_client->idef());
+ bool move = true;
// If source stack cannot be added to destination stack at all,
// they are swapped
- if ((leftover.count == stack_from.count) &&
- (leftover.name == stack_from.name)) {
- m_selected_amount = stack_to.count;
- // In case the server doesn't directly swap them but instead
- // moves stack_to somewhere else, set this
- m_selected_content_guess = stack_to;
- m_selected_content_guess_inventory = s.inventoryloc;
+ if (leftover.count == stack_from.count &&
+ leftover.name == stack_from.name) {
+
+ if (m_selected_swap.empty()) {
+ m_selected_amount = stack_to.count;
+ m_selected_dragging = false;
+
+ // WARNING: BLACK MAGIC, BUT IN A REDUCED SET
+ // Skip next validation checks due async inventory calls
+ m_selected_swap = stack_to;
+ } else {
+ move = false;
+ }
}
// Source stack goes fully into destination stack
else if (leftover.empty()) {
m_selected_amount -= move_amount;
- m_selected_content_guess = ItemStack(); // Clear
}
// Source stack goes partly into destination stack
else {
move_amount -= leftover.count;
m_selected_amount -= move_amount;
- m_selected_content_guess = ItemStack(); // Clear
}
- infostream << "Handing IAction::Move to manager" << std::endl;
- IMoveAction *a = new IMoveAction();
- a->count = move_amount;
- a->from_inv = m_selected_item->inventoryloc;
- a->from_list = m_selected_item->listname;
- a->from_i = m_selected_item->i;
- a->to_inv = s.inventoryloc;
- a->to_list = s.listname;
- a->to_i = s.i;
- m_invmgr->inventoryAction(a);
+ if (move) {
+ infostream << "Handing IAction::Move to manager" << std::endl;
+ IMoveAction *a = new IMoveAction();
+ a->count = move_amount;
+ a->from_inv = m_selected_item->inventoryloc;
+ a->from_list = m_selected_item->listname;
+ a->from_i = m_selected_item->i;
+ a->to_inv = s.inventoryloc;
+ a->to_list = s.listname;
+ a->to_i = s.i;
+ m_invmgr->inventoryAction(a);
+ }
} else if (shift_move_amount > 0) {
u32 mis = m_inventory_rings.size();
u32 i = 0;
break;
ItemStack stack_from = list_from->getItem(s.i);
assert(shift_move_amount <= stack_from.count);
- if (m_client->getProtoVersion() >= 25) {
- infostream << "Handing IAction::Move to manager" << std::endl;
- IMoveAction *a = new IMoveAction();
- a->count = shift_move_amount;
- a->from_inv = s.inventoryloc;
- a->from_list = s.listname;
- a->from_i = s.i;
- a->to_inv = to_inv_sp.inventoryloc;
- a->to_list = to_inv_sp.listname;
- a->move_somewhere = true;
- m_invmgr->inventoryAction(a);
- } else {
- // find a place (or more than one) to add the new item
- u32 ilt_size = list_to->getSize();
- ItemStack leftover;
- for (u32 slot_to = 0; slot_to < ilt_size
- && shift_move_amount > 0; slot_to++) {
- list_to->itemFits(slot_to, stack_from, &leftover);
- if (leftover.count < stack_from.count) {
- infostream << "Handing IAction::Move to manager" << std::endl;
- IMoveAction *a = new IMoveAction();
- a->count = MYMIN(shift_move_amount,
- (u32) (stack_from.count - leftover.count));
- shift_move_amount -= a->count;
- a->from_inv = s.inventoryloc;
- a->from_list = s.listname;
- a->from_i = s.i;
- a->to_inv = to_inv_sp.inventoryloc;
- a->to_list = to_inv_sp.listname;
- a->to_i = slot_to;
- m_invmgr->inventoryAction(a);
- stack_from = leftover;
- }
- }
- }
+
+ infostream << "Handing IAction::Move to manager" << std::endl;
+ IMoveAction *a = new IMoveAction();
+ a->count = shift_move_amount;
+ a->from_inv = s.inventoryloc;
+ a->from_list = s.listname;
+ a->from_i = s.i;
+ a->to_inv = to_inv_sp.inventoryloc;
+ a->to_list = to_inv_sp.listname;
+ a->move_somewhere = true;
+ m_invmgr->inventoryAction(a);
} while (0);
} else if (drop_amount > 0) {
- m_selected_content_guess = ItemStack(); // Clear
-
// Send IAction::Drop
assert(m_selected_item && m_selected_item->isValid());
if (m_selected_item == NULL ||
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
- m_selected_content_guess = ItemStack(); // Clear
-
assert(inv_s);
// Send IACTION_CRAFT
// If m_selected_amount has been decreased to zero, deselect
if (m_selected_amount == 0) {
+ m_selected_swap.clear();
delete m_selected_item;
m_selected_item = NULL;
m_selected_amount = 0;
m_selected_dragging = false;
- m_selected_content_guess = ItemStack();
}
m_old_pointer = m_pointer;
}