GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/inventorywindow.cpp Lines: 180 499 36.1 %
Date: 2018-09-20 Branches: 160 743 21.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2018  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "gui/windows/inventorywindow.h"
24
25
#include "configuration.h"
26
27
#include "being/playerinfo.h"
28
29
#include "const/sound.h"
30
31
#include "enums/gui/layouttype.h"
32
33
#include "input/inputmanager.h"
34
35
#include "gui/gui.h"
36
37
#include "gui/fonts/font.h"
38
39
#include "gui/models/sortlistmodelinv.h"
40
41
#include "gui/popups/itempopup.h"
42
#include "gui/popups/popupmenu.h"
43
#include "gui/popups/textpopup.h"
44
45
#include "gui/windows/confirmdialog.h"
46
#include "gui/windows/itemamountwindow.h"
47
#include "gui/windows/npcdialog.h"
48
#include "gui/windows/setupwindow.h"
49
#include "gui/windows/tradewindow.h"
50
51
#include "gui/widgets/button.h"
52
#include "gui/widgets/createwidget.h"
53
#include "gui/widgets/containerplacer.h"
54
#include "gui/widgets/dropdown.h"
55
#include "gui/widgets/itemcontainer.h"
56
#include "gui/widgets/layout.h"
57
#include "gui/widgets/progressbar.h"
58
#include "gui/widgets/scrollarea.h"
59
#include "gui/widgets/tabstrip.h"
60
#include "gui/widgets/textfield.h"
61
#include "gui/widgets/windowcontainer.h"
62
63
#include "listeners/insertcardlistener.h"
64
65
#include "net/npchandler.h"
66
67
#include "resources/iteminfo.h"
68
69
#include "resources/db/unitsdb.h"
70
71
#include "resources/item/item.h"
72
73
#include "utils/delete2.h"
74
#include "utils/foreach.h"
75
76
#include "debug.h"
77
78
InventoryWindow *inventoryWindow = nullptr;
79
InventoryWindow *storageWindow = nullptr;
80
InventoryWindow *cartWindow = nullptr;
81
1
InventoryWindow::WindowList InventoryWindow::invInstances;
82
1
InsertCardListener insertCardListener;
83
84
1
InventoryWindow::InventoryWindow(Inventory *const inventory) :
85
    Window("Inventory", Modal_false, nullptr, "inventory.xml"),
86
    ActionListener(),
87
    KeyListener(),
88
    SelectionListener(),
89
    InventoryListener(),
90
    AttributeListener(),
91
    mInventory(inventory),
92
    mItems(new ItemContainer(this, mInventory, 100000,
93

1
        ShowEmptyRows_false, ForceQuantity_false)),
94
    mUseButton(nullptr),
95
    mDropButton(nullptr),
96
    mOutfitButton(nullptr),
97
    mShopButton(nullptr),
98
    mCartButton(nullptr),
99
    mEquipmentButton(nullptr),
100
    mStoreButton(nullptr),
101
    mRetrieveButton(nullptr),
102
    mInvCloseButton(nullptr),
103
    mWeightBar(nullptr),
104
    mSlotsBar(new ProgressBar(this, 0.0F, 100, 0,
105
        ProgressColorId::PROG_INVY_SLOTS,
106

1
        "slotsprogressbar.xml", "slotsprogressbar_fill.xml")),
107
    mFilter(nullptr),
108
2
    mSortModel(new SortListModelInv),
109
1
    mSortDropDown(new DropDown(this, mSortModel, false,
110

2
        Modal_false, this, "sort")),
111
    mNameFilter(new TextField(this, "", LoseFocusOnTab_true,
112

1
        this, "namefilter", true)),
113
    mSortDropDownCell(nullptr),
114
    mNameFilterCell(nullptr),
115
    mFilterCell(nullptr),
116
    mSlotsBarCell(nullptr),
117
    mSplit(false),
118




31
    mCompactMode(false)
119
{
120
3
    mSlotsBar->setColor(getThemeColor(ThemeColorId::SLOTS_BAR, 255U),
121
1
        getThemeColor(ThemeColorId::SLOTS_BAR_OUTLINE, 255U));
122
123
1
    if (inventory != nullptr)
124
    {
125

7
        setCaption(gettext(inventory->getName().c_str()));
126
3
        setWindowName(inventory->getName());
127
1
        switch (inventory->getType())
128
        {
129
            case InventoryType::Inventory:
130
            case InventoryType::Trade:
131
            case InventoryType::Npc:
132
            case InventoryType::Vending:
133
            case InventoryType::MailEdit:
134
            case InventoryType::MailView:
135
            case InventoryType::Craft:
136
            case InventoryType::TypeEnd:
137
            default:
138

4
                mSortDropDown->setSelected(config.getIntValue(
139
1
                    "inventorySortOrder"));
140
1
                break;
141
            case InventoryType::Storage:
142
                mSortDropDown->setSelected(config.getIntValue(
143
                    "storageSortOrder"));
144
                break;
145
            case InventoryType::Cart:
146
                mSortDropDown->setSelected(config.getIntValue(
147
                    "cartSortOrder"));
148
                break;
149
        };
150
    }
151
    else
152
    {
153
        // TRANSLATORS: inventory window name
154
        setCaption(_("Inventory"));
155
        setWindowName("Inventory");
156
        mSortDropDown->setSelected(0);
157
    }
158
159

2
    if ((setupWindow != nullptr) &&
160

1
        (inventory != nullptr) &&
161
        inventory->getType() != InventoryType::Storage)
162
    {
163
        setupWindow->registerWindowForReset(this);
164
    }
165
166
1
    setResizable(true);
167
1
    setCloseButton(true);
168
2
    setSaveVisible(true);
169
1
    setStickyButtonLock(true);
170
171
1
    if (mainGraphics->mWidth > 600)
172
1
        setDefaultSize(450, 310, ImagePosition::CENTER, 0, 0);
173
    else
174
        setDefaultSize(387, 307, ImagePosition::CENTER, 0, 0);
175
1
    setMinWidth(310);
176
1
    setMinHeight(179);
177
1
    addKeyListener(this);
178
179
2
    mItems->addSelectionListener(this);
180
181

4
    const int size = config.getIntValue("fontSize");
182

3
    mFilter = new TabStrip(this, "filter_" + getWindowName(), size + 16, 0);
183
1
    mFilter->addActionListener(this);
184
5
    mFilter->setActionEventId("tag_");
185
2
    mFilter->setSelectable(false);
186
187

2
    StringVect tags = ItemDB::getTags();
188
2
    const size_t sz = tags.size();
189
1
    for (size_t f = 0; f < sz; f ++)
190
        mFilter->addButton(tags[f], tags[f], false);
191
192
1
    if (mInventory == nullptr)
193
    {
194
        invInstances.push_back(this);
195
        return;
196
    }
197
198
1
    ScrollArea *const invenScroll = new ScrollArea(this, mItems,
199

4
        fromBool(getOptionBool("showbackground", false), Opaque),
200

5
        "inventory_background.xml");
201
1
    invenScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
202
203

2
    switch (mInventory->getType())
204
    {
205
        case InventoryType::Inventory:
206
        {
207
            // TRANSLATORS: inventory button
208
4
            const std::string equip = _("Equip");
209
            // TRANSLATORS: inventory button
210
4
            const std::string use = _("Use");
211
            // TRANSLATORS: inventory button
212
4
            const std::string unequip = _("Unequip");
213
214

1
            std::string longestUseString = getFont()->getWidth(equip) >
215

2
                getFont()->getWidth(use) ? equip : use;
216
217

2
            if (getFont()->getWidth(longestUseString) <
218

1
                getFont()->getWidth(unequip))
219
            {
220
                longestUseString = unequip;
221
            }
222
223
1
            mUseButton = new Button(this,
224
                longestUseString,
225
                "use",
226
                BUTTON_SKIN,
227

4
                this);
228
1
            mDropButton = new Button(this,
229
                // TRANSLATORS: inventory button
230
1
                _("Drop..."),
231
                "drop",
232
                BUTTON_SKIN,
233


7
                this);
234
1
            mOutfitButton = new Button(this,
235
                // TRANSLATORS: inventory outfits button
236
1
                _("O"),
237
                "outfit",
238
                BUTTON_SKIN,
239


7
                this);
240
1
            mCartButton = new Button(this,
241
                // TRANSLATORS: inventory cart button
242
1
                _("C"),
243
                "cart",
244
                BUTTON_SKIN,
245


7
                this);
246
1
            mShopButton = new Button(this,
247
                // TRANSLATORS: inventory shop button
248
1
                _("S"),
249
                "shop",
250
                BUTTON_SKIN,
251


7
                this);
252
1
            mEquipmentButton = new Button(this,
253
                // TRANSLATORS: inventory equipment button
254
1
                _("E"),
255
                "equipment",
256
                BUTTON_SKIN,
257


7
                this);
258
1
            mWeightBar = new ProgressBar(this, 0.0F, 100, 0,
259
                ProgressColorId::PROG_WEIGHT,
260


7
                "weightprogressbar.xml", "weightprogressbar_fill.xml");
261
3
            mWeightBar->setColor(getThemeColor(ThemeColorId::WEIGHT_BAR, 255U),
262
1
                getThemeColor(ThemeColorId::WEIGHT_BAR_OUTLINE, 255U));
263
264
            // TRANSLATORS: outfits button tooltip
265
5
            mOutfitButton->setDescription(_("Outfits"));
266
            // TRANSLATORS: cart button tooltip
267
5
            mCartButton->setDescription(_("Cart"));
268
            // TRANSLATORS: shop button tooltip
269
5
            mShopButton->setDescription(_("Shop"));
270
            // TRANSLATORS: equipment button tooltip
271
5
            mEquipmentButton->setDescription(_("Equipment"));
272
273
1
            place(0, 0, mWeightBar, 4, 1);
274
1
            mSlotsBarCell = &place(4, 0, mSlotsBar, 4, 1);
275

1
            mSortDropDownCell = &place(8, 0, mSortDropDown, 3, 1);
276
277
2
            mFilterCell = &place(0, 1, mFilter, 10, 1).setPadding(3);
278
1
            mNameFilterCell = &place(8, 1, mNameFilter, 3, 1);
279
280
2
            place(0, 2, invenScroll, 11, 1).setPadding(3);
281
1
            place(0, 3, mUseButton, 1, 1);
282
1
            place(1, 3, mDropButton, 1, 1);
283
1
            ContainerPlacer placer = getPlacer(10, 3);
284
1
            placer(0, 0, mShopButton, 1, 1);
285
1
            placer(1, 0, mOutfitButton, 1, 1);
286
1
            placer(2, 0, mCartButton, 1, 1);
287
1
            placer(3, 0, mEquipmentButton, 1, 1);
288
289
1
            updateWeight();
290
            break;
291
        }
292
293
        case InventoryType::Storage:
294
        {
295
            mStoreButton = new Button(this,
296
                // TRANSLATORS: storage button
297
                _("Store"),
298
                "store",
299
                BUTTON_SKIN,
300
                this);
301
            mRetrieveButton = new Button(this,
302
                // TRANSLATORS: storage button
303
                _("Retrieve"),
304
                "retrieve",
305
                BUTTON_SKIN,
306
                this);
307
            mInvCloseButton = new Button(this,
308
                // TRANSLATORS: storage button
309
                _("Close"),
310
                "close",
311
                BUTTON_SKIN,
312
                this);
313
314
            mSlotsBarCell = &place(0, 0, mSlotsBar, 6, 1);
315
            mSortDropDownCell = &place(6, 0, mSortDropDown, 1, 1);
316
317
            mFilterCell = &place(0, 1, mFilter, 7, 1).setPadding(3);
318
            mNameFilterCell = &place(6, 1, mNameFilter, 1, 1);
319
320
            place(0, 2, invenScroll, 7, 4);
321
            place(0, 6, mStoreButton, 1, 1);
322
            place(1, 6, mRetrieveButton, 1, 1);
323
            place(6, 6, mInvCloseButton, 1, 1);
324
            break;
325
        }
326
327
        case InventoryType::Cart:
328
        {
329
            mStoreButton = new Button(this,
330
                // TRANSLATORS: storage button
331
                _("Store"),
332
                "store",
333
                BUTTON_SKIN,
334
                this);
335
            mRetrieveButton = new Button(this,
336
                // TRANSLATORS: storage button
337
                _("Retrieve"),
338
                "retrieve",
339
                BUTTON_SKIN,
340
                this);
341
            mInvCloseButton = new Button(this,
342
                // TRANSLATORS: storage button
343
                _("Close"),
344
                "close",
345
                BUTTON_SKIN,
346
                this);
347
348
            mWeightBar = new ProgressBar(this, 0.0F, 100, 0,
349
                ProgressColorId::PROG_WEIGHT,
350
                "weightprogressbar.xml", "weightprogressbar_fill.xml");
351
            mWeightBar->setColor(getThemeColor(ThemeColorId::WEIGHT_BAR, 255U),
352
                getThemeColor(ThemeColorId::WEIGHT_BAR_OUTLINE, 255U));
353
354
            mSlotsBarCell = &place(3, 0, mSlotsBar, 3, 1);
355
            mSortDropDownCell = &place(6, 0, mSortDropDown, 1, 1);
356
357
            mFilterCell = &place(0, 1, mFilter, 7, 1).setPadding(3);
358
            mNameFilterCell = &place(6, 1, mNameFilter, 1, 1);
359
360
            place(0, 0, mWeightBar, 3, 1);
361
            place(0, 2, invenScroll, 7, 4);
362
            place(0, 6, mStoreButton, 1, 1);
363
            place(1, 6, mRetrieveButton, 1, 1);
364
            place(6, 6, mInvCloseButton, 1, 1);
365
            break;
366
        }
367
368
        default:
369
        case InventoryType::Trade:
370
        case InventoryType::Npc:
371
        case InventoryType::Vending:
372
        case InventoryType::MailEdit:
373
        case InventoryType::MailView:
374
        case InventoryType::Craft:
375
        case InventoryType::TypeEnd:
376
            break;
377
    };
378
379
1
    Layout &layout = getLayout();
380
1
    layout.setRowHeight(2, LayoutType::SET);
381
382
1
    mInventory->addInventoyListener(this);
383
384
2
    invInstances.push_back(this);
385
386
1
    if (inventory->isMainInventory())
387
    {
388
1
        updateDropButton();
389
    }
390
    else
391
    {
392
        if (!invInstances.empty())
393
            invInstances.front()->updateDropButton();
394
    }
395
396
1
    loadWindowState();
397
2
    enableVisibleSound(true);
398
}
399
400
1
void InventoryWindow::postInit()
401
{
402
1
    Window::postInit();
403
1
    slotsChanged(mInventory);
404
405
1
    mItems->setSortType(mSortDropDown->getSelected());
406
1
    widgetResized(Event(nullptr));
407

2
    if (mInventory != nullptr &&
408
2
        mInventory->getType() == InventoryType::Storage)
409
    {
410
        setVisible(Visible_true);
411
    }
412
1
}
413
414
7
InventoryWindow::~InventoryWindow()
415
{
416
1
    invInstances.remove(this);
417
1
    if (mInventory != nullptr)
418
1
        mInventory->removeInventoyListener(this);
419
1
    if (!invInstances.empty())
420
        invInstances.front()->updateDropButton();
421
422
1
    mSortDropDown->hideDrop(false);
423
2
    delete2(mSortModel);
424
2
}
425
426
1
void InventoryWindow::storeSortOrder() const
427
{
428
1
    if (mInventory != nullptr)
429
    {
430
2
        switch (mInventory->getType())
431
        {
432
            case InventoryType::Inventory:
433
            case InventoryType::Trade:
434
            case InventoryType::Npc:
435
            case InventoryType::Vending:
436
            case InventoryType::MailEdit:
437
            case InventoryType::MailView:
438
            case InventoryType::Craft:
439
            case InventoryType::TypeEnd:
440
            default:
441
4
                config.setValue("inventorySortOrder",
442
2
                    mSortDropDown->getSelected());
443
1
                break;
444
            case InventoryType::Storage:
445
                config.setValue("storageSortOrder",
446
                    mSortDropDown->getSelected());
447
                break;
448
            case InventoryType::Cart:
449
                config.setValue("cartSortOrder",
450
                    mSortDropDown->getSelected());
451
                break;
452
        };
453
    }
454
1
}
455
456
1
void InventoryWindow::action(const ActionEvent &event)
457
{
458
1
    const std::string &eventId = event.getId();
459
1
    if (eventId == "outfit")
460
    {
461
        inputManager.executeAction(InputAction::WINDOW_OUTFIT);
462
    }
463
1
    else if (eventId == "shop")
464
    {
465
        inputManager.executeAction(InputAction::WINDOW_SHOP);
466
    }
467
1
    else if (eventId == "equipment")
468
    {
469
        inputManager.executeAction(InputAction::WINDOW_EQUIPMENT);
470
    }
471
1
    else if (eventId == "cart")
472
    {
473
        inputManager.executeAction(InputAction::WINDOW_CART);
474
    }
475
1
    else if (eventId == "close")
476
    {
477
        close();
478
    }
479
1
    else if (eventId == "store")
480
    {
481
        if (inventoryWindow == nullptr || !inventoryWindow->isWindowVisible())
482
            return;
483
484
        Item *const item = inventoryWindow->getSelectedItem();
485
486
        if (item == nullptr)
487
            return;
488
489
        if (storageWindow != nullptr)
490
        {
491
            ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreAdd,
492
                this,
493
                item,
494
                0,
495
                0);
496
        }
497
        else if ((cartWindow != nullptr) && cartWindow->isWindowVisible())
498
        {
499
            ItemAmountWindow::showWindow(ItemAmountWindowUsage::CartAdd,
500
                this,
501
                item,
502
                0,
503
                0);
504
        }
505
    }
506
1
    else if (eventId == "sort")
507
    {
508
1
        mItems->setSortType(mSortDropDown->getSelected());
509
1
        storeSortOrder();
510
1
        return;
511
    }
512
    else if (eventId == "namefilter")
513
    {
514
        mItems->setName(mNameFilter->getText());
515
        mItems->updateMatrix();
516
    }
517
    else if (eventId.find("tag_") == 0u)
518
    {
519
        std::string tagName = event.getId().substr(4);
520
        mItems->setFilter(ItemDB::getTagId(tagName));
521
        return;
522
    }
523
524
    Item *const item = mItems->getSelectedItem();
525
526
    if (item == nullptr)
527
        return;
528
529
    if (eventId == "use")
530
    {
531
        PlayerInfo::useEquipItem(item, 0, Sfx_true);
532
    }
533
    if (eventId == "equip")
534
    {
535
        PlayerInfo::useEquipItem2(item, 0, Sfx_true);
536
    }
537
    else if (eventId == "drop")
538
    {
539
        if (isStorageActive())
540
        {
541
            inventoryHandler->moveItem2(InventoryType::Inventory,
542
                item->getInvIndex(),
543
                item->getQuantity(),
544
                InventoryType::Storage);
545
        }
546
        else if ((cartWindow != nullptr) && cartWindow->isWindowVisible())
547
        {
548
            inventoryHandler->moveItem2(InventoryType::Inventory,
549
                item->getInvIndex(),
550
                item->getQuantity(),
551
                InventoryType::Cart);
552
        }
553
        else
554
        {
555
            if (PlayerInfo::isItemProtected(item->getId()))
556
                return;
557
558
            if (inputManager.isActionActive(InputAction::STOP_ATTACK))
559
            {
560
                PlayerInfo::dropItem(item, item->getQuantity(), Sfx_true);
561
            }
562
            else
563
            {
564
                ItemAmountWindow::showWindow(ItemAmountWindowUsage::ItemDrop,
565
                    this,
566
                    item,
567
                    0,
568
                    0);
569
            }
570
        }
571
    }
572
    else if (eventId == "split")
573
    {
574
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::ItemSplit,
575
            this,
576
            item,
577
            item->getQuantity() - 1,
578
            9);
579
    }
580
    else if (eventId == "retrieve")
581
    {
582
        if (storageWindow != nullptr)
583
        {
584
            ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreRemove,
585
                this,
586
                item,
587
                0,
588
                0);
589
        }
590
        else if ((cartWindow != nullptr) && cartWindow->isWindowVisible())
591
        {
592
            ItemAmountWindow::showWindow(ItemAmountWindowUsage::CartRemove,
593
                this,
594
                item,
595
                0,
596
                0);
597
        }
598
    }
599
}
600
601
Item *InventoryWindow::getSelectedItem() const
602
{
603
    return mItems->getSelectedItem();
604
}
605
606
void InventoryWindow::unselectItem()
607
{
608
    mItems->selectNone();
609
}
610
611
void InventoryWindow::widgetHidden(const Event &event)
612
{
613
    Window::widgetHidden(event);
614
    if (itemPopup != nullptr)
615
        itemPopup->setVisible(Visible_false);
616
}
617
618
void InventoryWindow::mouseClicked(MouseEvent &event)
619
{
620
    Window::mouseClicked(event);
621
622
    const int clicks = event.getClickCount();
623
624
    if (clicks == 2 && (gui != nullptr))
625
        gui->resetClickCount();
626
627
    const bool mod = (isStorageActive() &&
628
        inputManager.isActionActive(InputAction::STOP_ATTACK));
629
630
    const bool mod2 = (tradeWindow != nullptr &&
631
        tradeWindow->isWindowVisible() &&
632
        inputManager.isActionActive(InputAction::STOP_ATTACK));
633
634
    if (mInventory != nullptr)
635
    {
636
        if (!mod && !mod2 && event.getButton() == MouseButton::RIGHT)
637
        {
638
            Item *const item = mItems->getSelectedItem();
639
640
            if (item == nullptr)
641
                return;
642
643
            /* Convert relative to the window coordinates to absolute screen
644
             * coordinates.
645
             */
646
            const int mx = event.getX() + getX();
647
            const int my = event.getY() + getY();
648
649
            if (popupMenu != nullptr)
650
            {
651
                popupMenu->showPopup(this,
652
                    mx, my,
653
                    item,
654
                    mInventory->getType());
655
            }
656
        }
657
    }
658
    else
659
    {
660
        return;
661
    }
662
663
    if (event.getButton() == MouseButton::LEFT ||
664
        event.getButton() == MouseButton::RIGHT)
665
    {
666
        Item *const item = mItems->getSelectedItem();
667
668
        if (item == nullptr)
669
            return;
670
671
        if (mod)
672
        {
673
            if (mInventory->isMainInventory())
674
            {
675
                if (event.getButton() == MouseButton::RIGHT)
676
                {
677
                    ItemAmountWindow::showWindow(
678
                        ItemAmountWindowUsage::StoreAdd,
679
                        inventoryWindow,
680
                        item,
681
                        0,
682
                        0);
683
                }
684
                else
685
                {
686
                    inventoryHandler->moveItem2(InventoryType::Inventory,
687
                        item->getInvIndex(),
688
                        item->getQuantity(),
689
                        InventoryType::Storage);
690
                }
691
            }
692
            else
693
            {
694
                if (event.getButton() == MouseButton::RIGHT)
695
                {
696
                    ItemAmountWindow::showWindow(
697
                        ItemAmountWindowUsage::StoreRemove,
698
                        inventoryWindow,
699
                        item,
700
                        0,
701
                        0);
702
                }
703
                else
704
                {
705
                    inventoryHandler->moveItem2(InventoryType::Storage,
706
                        item->getInvIndex(),
707
                        item->getQuantity(),
708
                        InventoryType::Inventory);
709
                }
710
            }
711
        }
712
        else if (mod2 && mInventory->isMainInventory())
713
        {
714
            if (PlayerInfo::isItemProtected(item->getId()))
715
                return;
716
            if (event.getButton() == MouseButton::RIGHT)
717
            {
718
                ItemAmountWindow::showWindow(ItemAmountWindowUsage::TradeAdd,
719
                    tradeWindow,
720
                    item,
721
                    0,
722
                    0);
723
            }
724
            else
725
            {
726
                if (tradeWindow != nullptr)
727
                    tradeWindow->tradeItem(item, item->getQuantity(), true);
728
            }
729
        }
730
        else if (clicks == 2)
731
        {
732
            if (mInventory->isMainInventory())
733
            {
734
                if (isStorageActive())
735
                {
736
                    ItemAmountWindow::showWindow(
737
                        ItemAmountWindowUsage::StoreAdd,
738
                        inventoryWindow,
739
                        item,
740
                        0,
741
                        0);
742
                }
743
                else if (tradeWindow != nullptr &&
744
                         tradeWindow->isWindowVisible())
745
                {
746
                    if (PlayerInfo::isItemProtected(item->getId()))
747
                        return;
748
                    ItemAmountWindow::showWindow(
749
                        ItemAmountWindowUsage::TradeAdd,
750
                        tradeWindow,
751
                        item,
752
                        0,
753
                        0);
754
                }
755
                else
756
                {
757
                    PlayerInfo::useEquipItem(item, 0, Sfx_true);
758
                }
759
            }
760
            else
761
            {
762
                if (isStorageActive())
763
                {
764
                    ItemAmountWindow::showWindow(
765
                        ItemAmountWindowUsage::StoreRemove,
766
                        inventoryWindow,
767
                        item,
768
                        0,
769
                        0);
770
                }
771
            }
772
        }
773
    }
774
}
775
776
void InventoryWindow::mouseMoved(MouseEvent &event)
777
{
778
    Window::mouseMoved(event);
779
    if (textPopup == nullptr)
780
        return;
781
782
    const Widget *const src = event.getSource();
783
    if (src == nullptr)
784
    {
785
        textPopup->hide();
786
        return;
787
    }
788
    const int x = event.getX();
789
    const int y = event.getY();
790
    const Rect &rect = mDimension;
791
    if (src == mSlotsBar || src == mWeightBar)
792
    {
793
        // TRANSLATORS: money label
794
        textPopup->show(rect.x + x, rect.y + y, strprintf(_("Money: %s"),
795
            UnitsDb::formatCurrency(PlayerInfo::getAttribute(
796
            Attributes::MONEY)).c_str()));
797
    }
798
    else
799
    {
800
        const Button *const btn = dynamic_cast<const Button *>(src);
801
        if (btn == nullptr)
802
        {
803
            textPopup->hide();
804
            return;
805
        }
806
        const std::string text = btn->getDescription();
807
        if (!text.empty())
808
            textPopup->show(x + rect.x, y + rect.y, text);
809
    }
810
}
811
812
void InventoryWindow::mouseExited(MouseEvent &event A_UNUSED)
813
{
814
    textPopup->hide();
815
}
816
817
void InventoryWindow::keyPressed(KeyEvent &event)
818
{
819
    if (event.getActionId() == InputAction::GUI_MOD)
820
        mSplit = true;
821
}
822
823
void InventoryWindow::keyReleased(KeyEvent &event)
824
{
825
    if (event.getActionId() == InputAction::GUI_MOD)
826
        mSplit = false;
827
}
828
829
void InventoryWindow::valueChanged(const SelectionEvent &event A_UNUSED)
830
{
831
    if ((mInventory == nullptr) || !mInventory->isMainInventory())
832
        return;
833
834
    Item *const item = mItems->getSelectedItem();
835
836
    if (mSplit && (item != nullptr) && inventoryHandler->
837
        canSplit(mItems->getSelectedItem()))
838
    {
839
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::ItemSplit,
840
            this,
841
            item,
842
            item->getQuantity() - 1,
843
            0);
844
    }
845
    updateButtons(item);
846
}
847
848
void InventoryWindow::updateButtons(const Item *item)
849
{
850
    if ((mInventory == nullptr) || !mInventory->isMainInventory())
851
        return;
852
853
    const Item *const selectedItem = mItems->getSelectedItem();
854
    if ((item != nullptr) && selectedItem != item)
855
        return;
856
857
    if (item == nullptr)
858
        item = selectedItem;
859
860
    if ((item == nullptr) || item->getQuantity() == 0)
861
    {
862
        if (mUseButton != nullptr)
863
            mUseButton->setEnabled(false);
864
        if (mDropButton != nullptr)
865
            mDropButton->setEnabled(false);
866
        return;
867
    }
868
869
    if (mDropButton != nullptr)
870
        mDropButton->setEnabled(true);
871
872
    if (mUseButton != nullptr)
873
    {
874
        const ItemInfo &info = item->getInfo();
875
        const std::string &str = (item->isEquipment() == Equipm_true
876
            && item->isEquipped() == Equipped_true)
877
            ? info.getUseButton2() : info.getUseButton();
878
        if (str.empty())
879
        {
880
            mUseButton->setEnabled(false);
881
            // TRANSLATORS: default use button name
882
            mUseButton->setCaption(_("Use"));
883
        }
884
        else
885
        {
886
            mUseButton->setEnabled(true);
887
            mUseButton->setCaption(str);
888
        }
889
    }
890
891
    updateDropButton();
892
}
893
894
void InventoryWindow::close()
895
{
896
    if (mInventory == nullptr)
897
    {
898
        Window::close();
899
        return;
900
    }
901
902
    switch (mInventory->getType())
903
    {
904
        case InventoryType::Inventory:
905
        case InventoryType::Cart:
906
            setVisible(Visible_false);
907
            break;
908
909
        case InventoryType::Storage:
910
            if (inventoryHandler != nullptr)
911
            {
912
                inventoryHandler->closeStorage();
913
                inventoryHandler->forgotStorage();
914
            }
915
            scheduleDelete();
916
            break;
917
918
        default:
919
        case InventoryType::Trade:
920
        case InventoryType::Npc:
921
        case InventoryType::Vending:
922
        case InventoryType::MailEdit:
923
        case InventoryType::MailView:
924
        case InventoryType::Craft:
925
        case InventoryType::TypeEnd:
926
            break;
927
    }
928
}
929
930
1
void InventoryWindow::updateWeight()
931
{
932

1
    if ((mInventory == nullptr) || (mWeightBar == nullptr))
933
        return;
934
2
    const InventoryTypeT type = mInventory->getType();
935
2
    if (type != InventoryType::Inventory &&
936
1
        type != InventoryType::Cart)
937
    {
938
        return;
939
    }
940
941
1
    const bool isInv = type == InventoryType::Inventory;
942
1
    const int total = PlayerInfo::getAttribute(isInv
943
1
        ? Attributes::TOTAL_WEIGHT : Attributes::CART_TOTAL_WEIGHT);
944
1
    const int max = PlayerInfo::getAttribute(isInv
945
1
        ? Attributes::MAX_WEIGHT : Attributes::CART_MAX_WEIGHT);
946
947
1
    if (max <= 0)
948
        return;
949
950
    // Adjust progress bar
951
    mWeightBar->setProgress(static_cast<float>(total)
952
        / static_cast<float>(max));
953
    mWeightBar->setText(strprintf("%s/%s",
954
        UnitsDb::formatWeight(total).c_str(),
955
        UnitsDb::formatWeight(max).c_str()));
956
}
957
958
1
void InventoryWindow::slotsChanged(const Inventory *const inventory)
959
{
960
1
    if (inventory == mInventory)
961
    {
962
2
        const int usedSlots = mInventory->getNumberOfSlotsUsed();
963
2
        const int maxSlots = mInventory->getSize();
964
965
1
        if (maxSlots != 0)
966
        {
967
2
            mSlotsBar->setProgress(static_cast<float>(usedSlots)
968
2
                / static_cast<float>(maxSlots));
969
        }
970
971
2
        mSlotsBar->setText(strprintf("%d/%d", usedSlots, maxSlots));
972
1
        mItems->updateMatrix();
973
    }
974
1
}
975
976
1
void InventoryWindow::updateDropButton()
977
{
978
1
    if (mDropButton == nullptr)
979
        return;
980
981

3
    if (isStorageActive() ||
982
1
        (cartWindow != nullptr && cartWindow->isWindowVisible()))
983
    {
984
        // TRANSLATORS: inventory button
985
        mDropButton->setCaption(_("Store"));
986
    }
987
    else
988
    {
989
1
        const Item *const item = mItems->getSelectedItem();
990

1
        if ((item != nullptr) && item->getQuantity() > 1)
991
        {
992
            // TRANSLATORS: inventory button
993
            mDropButton->setCaption(_("Drop..."));
994
        }
995
        else
996
        {
997
            // TRANSLATORS: inventory button
998
5
            mDropButton->setCaption(_("Drop"));
999
        }
1000
    }
1001
}
1002
1003
bool InventoryWindow::isInputFocused() const
1004
{
1005
    return (mNameFilter != nullptr) && mNameFilter->isFocused();
1006
}
1007
1008
bool InventoryWindow::isAnyInputFocused()
1009
{
1010
    FOR_EACH (WindowList::const_iterator, it, invInstances)
1011
    {
1012
        if (((*it) != nullptr) && (*it)->isInputFocused())
1013
            return true;
1014
    }
1015
    return false;
1016
}
1017
1018
InventoryWindow *InventoryWindow::getFirstVisible()
1019
{
1020
    std::set<Widget*> list;
1021
    FOR_EACH (WindowList::const_iterator, it, invInstances)
1022
    {
1023
        if (((*it) != nullptr) && (*it)->isWindowVisible())
1024
            list.insert(*it);
1025
    }
1026
    return dynamic_cast<InventoryWindow*>(
1027
        windowContainer->findFirstWidget(list));
1028
}
1029
1030
void InventoryWindow::nextTab()
1031
{
1032
    const InventoryWindow *const window = getFirstVisible();
1033
    if (window != nullptr)
1034
        window->mFilter->nextTab();
1035
}
1036
1037
void InventoryWindow::prevTab()
1038
{
1039
    const InventoryWindow *const window = getFirstVisible();
1040
    if (window != nullptr)
1041
        window->mFilter->prevTab();
1042
}
1043
1044
2
void InventoryWindow::widgetResized(const Event &event)
1045
{
1046
2
    Window::widgetResized(event);
1047
1048
2
    if (mInventory == nullptr)
1049
        return;
1050
4
    const InventoryTypeT type = mInventory->getType();
1051
4
    if (type != InventoryType::Inventory &&
1052
2
        type != InventoryType::Cart)
1053
    {
1054
        return;
1055
    }
1056
1057
4
    if (getWidth() < 600)
1058
    {
1059
2
        if (!mCompactMode)
1060
        {
1061
1
            mNameFilter->setVisible(Visible_false);
1062
2
            mNameFilterCell->setType(LayoutCell::NONE);
1063
3
            mFilterCell->setWidth(mFilterCell->getWidth() + 3);
1064
1
            mCompactMode = true;
1065
        }
1066
    }
1067
    else if (mCompactMode)
1068
    {
1069
        mNameFilter->setVisible(Visible_true);
1070
        mNameFilterCell->setType(LayoutCell::WIDGET);
1071
        mFilterCell->setWidth(mFilterCell->getWidth() - 3);
1072
        mCompactMode = false;
1073
    }
1074
}
1075
1076
1
void InventoryWindow::setVisible(Visible visible)
1077
{
1078
1
    if (visible == Visible_false)
1079
1
        mSortDropDown->hideDrop(true);
1080
1
    Window::setVisible(visible);
1081
1
}
1082
1083
void InventoryWindow::unsetInventory()
1084
{
1085
    if (mInventory != nullptr)
1086
    {
1087
        mInventory->removeInventoyListener(this);
1088
        if (mItems != nullptr)
1089
            mItems->unsetInventory();
1090
    }
1091
    mInventory = nullptr;
1092
}
1093
1094
void InventoryWindow::attributeChanged(const AttributesT id,
1095
                                       const int64_t oldVal A_UNUSED,
1096
                                       const int64_t newVal A_UNUSED)
1097
{
1098
    if (id == Attributes::TOTAL_WEIGHT
1099
        || id == Attributes::MAX_WEIGHT
1100
        || id == Attributes::CART_TOTAL_WEIGHT
1101
        || id == Attributes::CART_MAX_WEIGHT)
1102
    {
1103
        updateWeight();
1104
    }
1105
}
1106
1107
void InventoryWindow::combineItems(const int index1,
1108
                                   const int index2)
1109
{
1110
    if (mInventory == nullptr)
1111
        return;
1112
    const Item *item1 = mInventory->getItem(index1);
1113
    if (item1 == nullptr)
1114
        return;
1115
    const Item *item2 = mInventory->getItem(index2);
1116
    if (item2 == nullptr)
1117
        return;
1118
1119
    if (item1->getType() != ItemType::Card)
1120
    {
1121
        const Item *tmpItem = item1;
1122
        item1 = item2;
1123
        item2 = tmpItem;
1124
    }
1125
1126
    ConfirmDialog *const confirmDlg = CREATEWIDGETR(ConfirmDialog,
1127
        // TRANSLATORS: question dialog title
1128
        _("Insert card request"),
1129
        // TRANSLATORS: question dialog message
1130
        strprintf(_("Insert %s into %s?"),
1131
        item1->getName().c_str(),
1132
        item2->getName().c_str()),
1133
        SOUND_REQUEST,
1134
        false,
1135
        Modal_true,
1136
        nullptr);
1137
    insertCardListener.itemIndex = item2->getInvIndex();
1138
    insertCardListener.cardIndex = item1->getInvIndex();
1139
    confirmDlg->addActionListener(&insertCardListener);
1140
}
1141
1142
void InventoryWindow::moveItemToCraft(const int craftSlot)
1143
{
1144
    if (npcHandler == nullptr)
1145
        return;
1146
1147
    Item *const item = mItems->getSelectedItem();
1148
    if (item == nullptr)
1149
        return;
1150
1151
    NpcDialog *const dialog = npcHandler->getCurrentNpcDialog();
1152
    if ((dialog != nullptr) &&
1153
        dialog->getInputState() == NpcInputState::ITEM_CRAFT)
1154
    {
1155
        if (item->getQuantity() > 1
1156
            && !inputManager.isActionActive(InputAction::STOP_ATTACK))
1157
        {
1158
            ItemAmountWindow::showWindow(ItemAmountWindowUsage::CraftAdd,
1159
                npcHandler->getCurrentNpcDialog(),
1160
                item,
1161
                0,
1162
                craftSlot);
1163
        }
1164
        else
1165
        {
1166
            dialog->addCraftItem(item, 1, craftSlot);
1167
        }
1168
    }
1169

3
}