GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/itemamountwindow.cpp Lines: 60 232 25.9 %
Date: 2021-03-17 Branches: 63 336 18.8 %

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-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "gui/windows/itemamountwindow.h"
25
26
#include "settings.h"
27
28
#include "being/playerinfo.h"
29
30
#include "input/keyboardconfig.h"
31
32
#include "gui/viewport.h"
33
34
#include "gui/models/itemsmodel.h"
35
36
#include "gui/popups/itempopup.h"
37
38
#include "gui/windows/maileditwindow.h"
39
#include "gui/windows/npcdialog.h"
40
#include "gui/windows/shopwindow.h"
41
#include "gui/windows/tradewindow.h"
42
43
#include "gui/widgets/button.h"
44
#include "gui/widgets/containerplacer.h"
45
#include "gui/widgets/createwidget.h"
46
#include "gui/widgets/dropdown.h"
47
#include "gui/widgets/icon.h"
48
#include "gui/widgets/inttextfield.h"
49
#include "gui/widgets/label.h"
50
#include "gui/widgets/slider.h"
51
52
#include "net/inventoryhandler.h"
53
#include "net/mail2handler.h"
54
#include "net/npchandler.h"
55
56
#include "resources/item/item.h"
57
58
#include "utils/delete2.h"
59
#include "utils/gettext.h"
60
61
#ifndef USE_SDL2
62
#include <cmath>
63
#endif  // USE_SDL2
64
65
#include "debug.h"
66
67
void ItemAmountWindow::finish(Item *const item,
68
                              const int amount,
69
                              const int price,
70
                              const ItemAmountWindowUsageT usage)
71
{
72
    if (item == nullptr)
73
        return;
74
    switch (usage)
75
    {
76
        case ItemAmountWindowUsage::TradeAdd:
77
            if (tradeWindow != nullptr)
78
                tradeWindow->tradeItem(item, amount, false);
79
            break;
80
        case ItemAmountWindowUsage::ItemDrop:
81
            PlayerInfo::dropItem(item, amount, Sfx_true);
82
            break;
83
        case ItemAmountWindowUsage::ItemSplit:
84
            inventoryHandler->splitItem(item, amount);
85
            break;
86
        case ItemAmountWindowUsage::StoreAdd:
87
            inventoryHandler->moveItem2(InventoryType::Inventory,
88
                item->getInvIndex(), amount, InventoryType::Storage);
89
            break;
90
        case ItemAmountWindowUsage::StoreRemove:
91
            inventoryHandler->moveItem2(InventoryType::Storage,
92
                item->getInvIndex(), amount, InventoryType::Inventory);
93
            break;
94
        case ItemAmountWindowUsage::ShopBuyAdd:
95
            if (shopWindow != nullptr)
96
                shopWindow->addBuyItem(item, amount, price);
97
            break;
98
        case ItemAmountWindowUsage::ShopSellAdd:
99
            if (shopWindow != nullptr)
100
                shopWindow->addSellItem(item, amount, price);
101
            break;
102
        case ItemAmountWindowUsage::CartAdd:
103
            inventoryHandler->moveItem2(InventoryType::Inventory,
104
                item->getInvIndex(), amount, InventoryType::Cart);
105
            break;
106
        case ItemAmountWindowUsage::CartRemove:
107
            inventoryHandler->moveItem2(InventoryType::Cart,
108
                item->getInvIndex(), amount, InventoryType::Inventory);
109
            break;
110
        case ItemAmountWindowUsage::MailAdd:
111
            if (settings.enableNewMailSystem)
112
            {
113
                mail2Handler->addItem(item, amount);
114
            }
115
            else if (mailEditWindow != nullptr)
116
            {
117
                mailEditWindow->addItem(item, amount);
118
            }
119
            break;
120
        case ItemAmountWindowUsage::CraftAdd:
121
        {
122
            NpcDialog *const dialog = npcHandler->getCurrentNpcDialog();
123
            if (dialog != nullptr)
124
                dialog->addCraftItem(item, amount, price);  // price as slot
125
            break;
126
        }
127
        default:
128
            break;
129
    }
130
}
131
132
1
ItemAmountWindow::ItemAmountWindow(const ItemAmountWindowUsageT usage,
133
                                   Window *const parent,
134
                                   Item *const item,
135
1
                                   const int maxRange) :
136
    Window("", Modal_false, parent, "amount.xml"),
137
    ActionListener(),
138
    KeyListener(),
139

1
    mItemAmountTextField(new IntTextField(this, 1, 0, 0, Enable_true, 0)),
140
    mItemPriceTextField(nullptr),
141
    mGPLabel(nullptr),
142
    mItem(item),
143
    mItemIcon(new Icon(this,
144

2
        item != nullptr ? item->getImage() : nullptr, AutoRelease_false)),
145

1
    mItemAmountSlide(new Slider(this, 1.0, maxRange, 1.0)),
146
    mItemPriceSlide(nullptr),
147
    mItemDropDown(nullptr),
148
    mItemsModal(nullptr),
149
    mPrice(0),
150
    mMax(maxRange),
151
    mUsage(usage),
152

13
    mEnabledKeyboard(keyboard.isEnabled())
153
{
154
1
    if (mItem == nullptr)
155
        return;
156
157
1
    if (usage == ItemAmountWindowUsage::ShopBuyAdd)
158
        mMax = 10000;
159
1
    else if (mMax == 0)
160
2
        mMax = mItem->getQuantity();
161
162
1
    keyboard.setEnabled(false);
163
164
1
    mItemAmountTextField->setRange(1, mMax);
165
1
    mItemAmountTextField->setWidth(35);
166
1
    mItemAmountTextField->addKeyListener(this);
167
168
1
    mItemAmountSlide->setHeight(10);
169
5
    mItemAmountSlide->setActionEventId("slide");
170
1
    mItemAmountSlide->addActionListener(this);
171
172
1
    if (mUsage == ItemAmountWindowUsage::ShopBuyAdd ||
173
        mUsage == ItemAmountWindowUsage::ShopSellAdd)
174
    {
175
        mItemPriceTextField = new IntTextField(this, 1, 0, 0, Enable_true, 0);
176
        mItemPriceTextField->setRange(1, 10000000);
177
        mItemPriceTextField->setWidth(35);
178
        mItemPriceTextField->addKeyListener(this);
179
180
        mItemPriceSlide = new Slider(this, 1.0, 10000000, 1.0);
181
        mItemPriceSlide->setHeight(10);
182
        mItemPriceSlide->setActionEventId("slidePrice");
183
        mItemPriceSlide->addActionListener(this);
184
185
        mGPLabel = new Label(this, " GP");
186
    }
187
188
1
    if (mUsage == ItemAmountWindowUsage::ShopBuyAdd)
189
    {
190
        mItemsModal = new ItemsModal;
191
        mItemDropDown = new DropDown(this,
192
            mItemsModal,
193
            false,
194
            Modal_false,
195
            nullptr,
196
            std::string());
197
        mItemDropDown->setActionEventId("itemType");
198
        mItemDropDown->addActionListener(this);
199
    }
200
201
    // Buttons
202
    Button *const minusAmountButton = new Button(this,
203
        // TRANSLATORS: item amount window button
204
1
        _("-"),
205
        "dec",
206
        BUTTON_SKIN,
207


7
        this);
208
    Button *const plusAmountButton = new Button(this,
209
        // TRANSLATORS: item amount window button
210
1
        _("+"),
211
        "inc",
212
        BUTTON_SKIN,
213


7
        this);
214
    Button *const okButton = new Button(this,
215
        // TRANSLATORS: item amount window button
216
1
        _("OK"),
217
        "ok",
218
        BUTTON_SKIN,
219


7
        this);
220
    Button *const cancelButton = new Button(this,
221
        // TRANSLATORS: item amount window button
222
1
        _("Cancel"),
223
        "cancel",
224
        BUTTON_SKIN,
225


7
        this);
226
    Button *const addAllButton = new Button(this,
227
        // TRANSLATORS: item amount window button
228
1
        _("All"),
229
        "all",
230
        BUTTON_SKIN,
231


7
        this);
232
233
1
    minusAmountButton->adjustSize();
234
2
    minusAmountButton->setWidth(plusAmountButton->getWidth());
235
236
    // Set positions
237
1
    ContainerPlacer placer(nullptr, nullptr);
238
1
    placer = getPlacer(0, 0);
239
1
    int n = 0;
240
1
    if (mUsage == ItemAmountWindowUsage::ShopBuyAdd)
241
    {
242
        placer(0, n, mItemDropDown, 8, 1);
243
        n++;
244
    }
245
1
    placer(1, n, minusAmountButton, 1, 1);
246
1
    placer(2, n, mItemAmountTextField, 3, 1);
247
1
    placer(5, n, plusAmountButton, 1, 1);
248
1
    placer(6, n, addAllButton, 1, 1);
249
250
1
    placer(0, n, mItemIcon, 1, 3);
251
1
    placer(1, n + 1, mItemAmountSlide, 7, 1);
252
253
1
    if (mUsage == ItemAmountWindowUsage::ShopBuyAdd ||
254
        mUsage == ItemAmountWindowUsage::ShopSellAdd)
255
    {
256
        Button *const minusPriceButton = new Button(this,
257
            // TRANSLATORS: item amount window button
258
            _("-"),
259
            "decPrice",
260
            BUTTON_SKIN,
261
            this);
262
        Button *const plusPriceButton = new Button(this,
263
            // TRANSLATORS: item amount window button
264
            _("+"),
265
            "incPrice",
266
            BUTTON_SKIN,
267
            this);
268
        minusPriceButton->adjustSize();
269
        minusPriceButton->setWidth(plusPriceButton->getWidth());
270
271
        placer(1, n + 2, minusPriceButton, 1, 1);
272
        placer(2, n + 2, mItemPriceTextField, 3, 1);
273
        placer(5, n + 2, plusPriceButton, 1, 1);
274
        placer(6, n + 2, mGPLabel, 1, 1);
275
276
        placer(1, n + 3, mItemPriceSlide, 7, 1);
277
        placer(4, n + 5, cancelButton, 1, 1);
278
        placer(5, n + 5, okButton, 1, 1);
279
    }
280
    else
281
    {
282
1
        placer(4, n + 2, cancelButton, 1, 1);
283
1
        placer(5, n + 2, okButton, 1, 1);
284
    }
285
286
1
    reflowLayout(225, 0);
287
288
1
    resetAmount();
289
290



1
    switch (usage)
291
    {
292
        case ItemAmountWindowUsage::TradeAdd:
293
            // TRANSLATORS: amount window message
294
            setCaption(_("Select amount of items to trade."));
295
            break;
296
        case ItemAmountWindowUsage::ItemDrop:
297
            // TRANSLATORS: amount window message
298
5
            setCaption(_("Select amount of items to drop."));
299
1
            break;
300
        case ItemAmountWindowUsage::StoreAdd:
301
            // TRANSLATORS: amount window message
302
            setCaption(_("Select amount of items to store."));
303
            break;
304
        case ItemAmountWindowUsage::MailAdd:
305
            // TRANSLATORS: amount window message
306
            setCaption(_("Select amount of items to send."));
307
            break;
308
        case ItemAmountWindowUsage::CraftAdd:
309
            // TRANSLATORS: amount window message
310
            setCaption(_("Select amount of items to craft."));
311
            break;
312
        case ItemAmountWindowUsage::CartAdd:
313
            // TRANSLATORS: amount window message
314
            setCaption(_("Select amount of items to store to cart."));
315
            break;
316
        case ItemAmountWindowUsage::StoreRemove:
317
            // TRANSLATORS: amount window message
318
            setCaption(_("Select amount of items to retrieve."));
319
            break;
320
        case ItemAmountWindowUsage::CartRemove:
321
            // TRANSLATORS: amount window message
322
            setCaption(_("Select amount of items to retrieve from cart."));
323
            break;
324
        case ItemAmountWindowUsage::ItemSplit:
325
            // TRANSLATORS: amount window message
326
            setCaption(_("Select amount of items to split."));
327
            break;
328
        case ItemAmountWindowUsage::ShopBuyAdd:
329
            // TRANSLATORS: amount window message
330
            setCaption(_("Add to buy shop."));
331
            break;
332
        case ItemAmountWindowUsage::ShopSellAdd:
333
            // TRANSLATORS: amount window message
334
            setCaption(_("Add to sell shop."));
335
            break;
336
        default:
337
            // TRANSLATORS: amount window message
338
            setCaption(_("Unknown."));
339
            break;
340
    }
341
342
1
    setLocationRelativeTo(getParentWindow());
343
344
1
    mItemIcon->addMouseListener(this);
345
}
346
347
1
void ItemAmountWindow::postInit()
348
{
349
1
    Window::postInit();
350
1
    setVisible(fromBool(mItem, Visible));
351
1
}
352
353
5
ItemAmountWindow::~ItemAmountWindow()
354
{
355
2
    delete2(mItemsModal)
356
2
}
357
358
// Show ItemTooltip
359
void ItemAmountWindow::mouseMoved(MouseEvent &event)
360
{
361
    Window::mouseMoved(event);
362
363
    if ((viewport == nullptr) || (itemPopup == nullptr))
364
        return;
365
366
    if (event.getSource() == mItemIcon)
367
    {
368
        itemPopup->setItem(mItem, false);
369
        itemPopup->position(viewport->mMouseX, viewport->mMouseY);
370
    }
371
}
372
373
// Hide ItemTooltip
374
void ItemAmountWindow::mouseExited(MouseEvent &event A_UNUSED)
375
{
376
    if (itemPopup != nullptr)
377
        itemPopup->setVisible(Visible_false);
378
}
379
380
void ItemAmountWindow::resetAmount()
381
{
382
1
    mItemAmountTextField->setValue(1);
383
}
384
385
void ItemAmountWindow::action(const ActionEvent &event)
386
{
387
    const std::string &eventId = event.getId();
388
    if (eventId == "cancel")
389
    {
390
        close();
391
        return;
392
    }
393
    else if (eventId == "ok")
394
    {
395
        if (mItemPriceTextField != nullptr)
396
        {
397
            finish(mItem,
398
                mItemAmountTextField->getValue(),
399
                mItemPriceTextField->getValue(),
400
                mUsage);
401
        }
402
        else
403
        {
404
            if (mUsage == ItemAmountWindowUsage::CraftAdd)
405
            {
406
                finish(mItem,
407
                    mItemAmountTextField->getValue(),
408
                    mPrice,
409
                    mUsage);
410
            }
411
            else
412
            {
413
                finish(mItem,
414
                    mItemAmountTextField->getValue(),
415
                    0,
416
                    mUsage);
417
            }
418
        }
419
        close();
420
        return;
421
    }
422
    else if (eventId == "itemType")
423
    {
424
        if ((mItemDropDown == nullptr) || (mItemsModal == nullptr))
425
            return;
426
427
        const int id = ItemDB::get(mItemsModal->getElementAt(
428
            mItemDropDown->getSelected())).getId();
429
430
        mItem = new Item(id,
431
            ItemType::Unknown,
432
            10000,
433
            0,
434
            ItemColor_one,
435
            Identified_true,
436
            Damaged_true,
437
            Favorite_false,
438
            Equipm_false,
439
            Equipped_false);
440
441
        if (mUsage == ItemAmountWindowUsage::ShopBuyAdd)
442
            mMax = 10000;
443
        else if (mMax == 0)
444
            mMax = mItem->getQuantity();
445
446
        mItemIcon->setImage(mItem->getImage());
447
    }
448
449
    int amount = mItemAmountTextField->getValue();
450
451
    if (eventId == "inc" && amount < mMax)
452
        amount++;
453
    else if (eventId == "dec" && amount > 1)
454
        amount--;
455
    else if (eventId == "all")
456
        amount = mMax;
457
    else if (eventId == "slide")
458
        amount = CAST_S32(mItemAmountSlide->getValue());
459
    mItemAmountTextField->setValue(amount);
460
    mItemAmountSlide->setValue(amount);
461
462
    if ((mItemPriceTextField != nullptr) && (mItemPriceSlide != nullptr))
463
    {
464
        if (mPrice > 7)
465
            mPrice = 7;
466
        else if (mPrice < 0)
467
            mPrice = 0;
468
469
        int price = 0;
470
471
        if (eventId == "incPrice")
472
        {
473
            mPrice++;
474
            price = CAST_S32(pow(10.0, mPrice));
475
            mItemPriceTextField->setValue(price);
476
            mItemPriceSlide->setValue(price);
477
        }
478
        else if (eventId == "decPrice")
479
        {
480
            mPrice--;
481
            price = CAST_S32(pow(10.0, mPrice));
482
            mItemPriceTextField->setValue(price);
483
            mItemPriceSlide->setValue(price);
484
        }
485
        else if (eventId == "slidePrice")
486
        {
487
            price = CAST_S32(mItemPriceSlide->getValue());
488
            if (price != 0)
489
                mPrice = CAST_S32(log(static_cast<float>(price)));
490
            else
491
                mPrice = 0;
492
            mItemPriceTextField->setValue(price);
493
            mItemPriceSlide->setValue(price);
494
        }
495
    }
496
}
497
498
void ItemAmountWindow::close()
499
{
500
    keyboard.setEnabled(mEnabledKeyboard);
501
    scheduleDelete();
502
}
503
504
void ItemAmountWindow::keyReleased(KeyEvent &event A_UNUSED)
505
{
506
    mItemAmountSlide->setValue(mItemAmountTextField->getValue());
507
}
508
509
void ItemAmountWindow::showWindow(const ItemAmountWindowUsageT usage,
510
                                  Window *const parent,
511
                                  Item *const item,
512
                                  int maxRange,
513
                                  int tag)
514
{
515
    if (item == nullptr)
516
        return;
517
518
    if (maxRange == 0)
519
        maxRange = item->getQuantity();
520
521
    if (usage != ItemAmountWindowUsage::ShopBuyAdd &&
522
        usage != ItemAmountWindowUsage::ShopSellAdd &&
523
        maxRange <= 1)
524
    {
525
        if (usage == ItemAmountWindowUsage::CraftAdd)
526
            finish(item, maxRange, tag, usage);
527
        else
528
            finish(item, maxRange, 0, usage);
529
    }
530
    else
531
    {
532
        ItemAmountWindow *const window = CREATEWIDGETR(ItemAmountWindow,
533
            usage, parent, item, maxRange);
534
        if (usage == ItemAmountWindowUsage::CraftAdd)
535
            window->mPrice = tag;
536
    }
537

3
}