GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/buydialog.cpp Lines: 139 365 38.1 %
Date: 2021-03-17 Branches: 103 440 23.4 %

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/buydialog.h"
25
26
#include "actormanager.h"
27
#include "configuration.h"
28
29
#include "being/being.h"
30
31
#include "enums/gui/layouttype.h"
32
33
#include "gui/windows/setupwindow.h"
34
#ifdef TMWA_SUPPORT
35
#include "gui/windows/tradewindow.h"
36
#endif  // TMWA_SUPPORT
37
38
#include "gui/models/shopitems.h"
39
#include "gui/models/sortlistmodelbuy.h"
40
41
#include "gui/widgets/button.h"
42
#include "gui/widgets/containerplacer.h"
43
#include "gui/widgets/createwidget.h"
44
#include "gui/widgets/dropdown.h"
45
#include "gui/widgets/inttextfield.h"
46
#include "gui/widgets/label.h"
47
#include "gui/widgets/layout.h"
48
#include "gui/widgets/scrollarea.h"
49
#include "gui/widgets/shoplistbox.h"
50
#include "gui/widgets/slider.h"
51
52
#include "net/adminhandler.h"
53
#include "net/buysellhandler.h"
54
#include "net/cashshophandler.h"
55
#include "net/markethandler.h"
56
#include "net/net.h"
57
#include "net/vendinghandler.h"
58
#include "net/npchandler.h"
59
60
#include "resources/iteminfo.h"
61
62
#include "resources/db/unitsdb.h"
63
64
#include "utils/delete2.h"
65
#include "utils/foreach.h"
66
67
#include <algorithm>
68
69
#include "debug.h"
70
71
namespace
72
{
73
    class SortItemPriceFunctor final
74
    {
75
        public:
76
            A_DEFAULT_COPY(SortItemPriceFunctor)
77
78
            bool operator() (const ShopItem *const item1,
79
                             const ShopItem *const item2) const
80
            {
81
                if ((item1 == nullptr) || (item2 == nullptr))
82
                    return false;
83
84
                const int price1 = item1->getPrice();
85
                const int price2 = item2->getPrice();
86
                if (price1 == price2)
87
                    return item1->getDisplayName() < item2->getDisplayName();
88
                return price1 < price2;
89
            }
90
    } itemPriceBuySorter;
91
92
    class SortItemNameFunctor final
93
    {
94
        public:
95
            A_DEFAULT_COPY(SortItemNameFunctor)
96
97
            bool operator() (const ShopItem *const item1,
98
                             const ShopItem *const item2) const
99
            {
100
                if ((item1 == nullptr) || (item2 == nullptr))
101
                    return false;
102
103
                const std::string &name1 = item1->getDisplayName();
104
                const std::string &name2 = item2->getDisplayName();
105
                if (name1 == name2)
106
                    return item1->getPrice() < item2->getPrice();
107
                return name1 < name2;
108
            }
109
    } itemNameBuySorter;
110
111
    class SortItemIdFunctor final
112
    {
113
        public:
114
            A_DEFAULT_COPY(SortItemIdFunctor)
115
116
            bool operator() (const ShopItem *const item1,
117
                             const ShopItem *const item2) const
118
            {
119
                if ((item1 == nullptr) || (item2 == nullptr))
120
                    return false;
121
122
                const int id1 = item1->getId();
123
                const int id2 = item2->getId();
124
                if (id1 == id2)
125
                    return item1->getPrice() < item2->getPrice();
126
                return id1 < id2;
127
            }
128
    } itemIdBuySorter;
129
130
    class SortItemWeightFunctor final
131
    {
132
        public:
133
            A_DEFAULT_COPY(SortItemWeightFunctor)
134
135
            bool operator() (const ShopItem *const item1,
136
                             const ShopItem *const item2) const
137
            {
138
                if ((item1 == nullptr) || (item2 == nullptr))
139
                    return false;
140
141
                const int weight1 = item1->getInfo().getWeight();
142
                const int weight2 = item2->getInfo().getWeight();
143
                if (weight1 == weight2)
144
                    return item1->getPrice() < item2->getPrice();
145
                return weight1 < weight2;
146
            }
147
    } itemWeightBuySorter;
148
149
    class SortItemAmountFunctor final
150
    {
151
        public:
152
            A_DEFAULT_COPY(SortItemAmountFunctor)
153
154
            bool operator() (const ShopItem *const item1,
155
                             const ShopItem *const item2) const
156
            {
157
                if ((item1 == nullptr) || (item2 == nullptr))
158
                    return false;
159
160
                const int amount1 = item1->getQuantity();
161
                const int amount2 = item2->getQuantity();
162
                if (amount1 == amount2)
163
                    return item1->getPrice() < item2->getPrice();
164
                return amount1 < amount2;
165
            }
166
    } itemAmountBuySorter;
167
168
    class SortItemTypeFunctor final
169
    {
170
        public:
171
            A_DEFAULT_COPY(SortItemTypeFunctor)
172
173
            bool operator() (const ShopItem *const item1,
174
                             const ShopItem *const item2) const
175
            {
176
                if ((item1 == nullptr) || (item2 == nullptr))
177
                    return false;
178
179
                const ItemDbTypeT type1 = item1->getInfo().getType();
180
                const ItemDbTypeT type2 = item2->getInfo().getType();
181
                if (type1 == type2)
182
                    return item1->getPrice() < item2->getPrice();
183
                return type1 < type2;
184
            }
185
    } itemTypeBuySorter;
186
}  // namespace
187
188
1
BuyDialog::DialogList BuyDialog::instances;
189
190
1
BuyDialog::BuyDialog() :
191
    // TRANSLATORS: buy dialog name
192
1
    Window(_("Create items"), Modal_false, nullptr, "buy.xml"),
193
    ActionListener(),
194
    SelectionListener(),
195
2
    mSortModel(new SortListModelBuy),
196
1
    mSortDropDown(new DropDown(this, mSortModel, false,
197

2
        Modal_false, this, "sort")),
198
    mFilterTextField(new TextField(this, "", LoseFocusOnTab_true,
199

1
        this, "namefilter", true)),
200
    mFilterLabel(nullptr),
201
    mNick(),
202
    mCurrency(),
203
    mNpcId(fromInt(Items, BeingId)),
204
    mMoney(0),
205
    mAmountItems(0),
206
    mMaxItems(0),
207


23
    mAdvanced(false)
208
{
209
1
    init();
210
1
}
211
212
1
BuyDialog::BuyDialog(const BeingId npcId,
213
1
                     const std::string &currency) :
214
    // TRANSLATORS: buy dialog name
215
1
    Window(_("Buy"), Modal_false, nullptr, "buy.xml"),
216
    ActionListener(),
217
    SelectionListener(),
218
    mSortModel(nullptr),
219
    mSortDropDown(nullptr),
220
    mFilterTextField(new TextField(this, "", LoseFocusOnTab_true,
221

1
        this, "namefilter", true)),
222
    mFilterLabel(nullptr),
223
    mNick(),
224
    mCurrency(currency),
225
    mNpcId(npcId),
226
    mMoney(0),
227
    mAmountItems(0),
228
    mMaxItems(0),
229


18
    mAdvanced(Net::getNetworkType() != ServerType::TMWATHENA)
230
{
231
1
    init();
232
1
}
233
234
#ifdef TMWA_SUPPORT
235
1
BuyDialog::BuyDialog(const std::string &nick,
236
1
                     const std::string &currency) :
237
    // TRANSLATORS: buy dialog name
238
1
    Window(_("Buy"), Modal_false, nullptr, "buy.xml"),
239
    ActionListener(),
240
    SelectionListener(),
241
2
    mSortModel(new SortListModelBuy),
242
1
    mSortDropDown(new DropDown(this, mSortModel, false,
243

2
        Modal_false, this, "sort")),
244
    mFilterTextField(new TextField(this, "", LoseFocusOnTab_true,
245

1
        this, "namefilter", true)),
246
    mFilterLabel(nullptr),
247
    mNick(nick),
248
    mCurrency(currency),
249
    mNpcId(fromInt(Nick, BeingId)),
250
    mMoney(0),
251
    mAmountItems(0),
252
    mMaxItems(0),
253


23
    mAdvanced(false)
254
{
255
1
    init();
256
1
}
257
#endif  // TMWA_SUPPORT
258
259
1
BuyDialog::BuyDialog(const Being *const being,
260
1
                     const std::string &currency) :
261
    // TRANSLATORS: buy dialog name
262
1
    Window(_("Buy"), Modal_false, nullptr, "buy.xml"),
263
    ActionListener(),
264
    SelectionListener(),
265
2
    mSortModel(new SortListModelBuy),
266
1
    mSortDropDown(new DropDown(this, mSortModel, false,
267

2
        Modal_false, this, "sort")),
268
    mFilterTextField(new TextField(this, "", LoseFocusOnTab_true,
269

1
        this, "namefilter", true)),
270
    mFilterLabel(nullptr),
271
1
    mNick(being != nullptr ? being->getName() : std::string()),
272
    mCurrency(currency),
273
    mNpcId(fromInt(Vending, BeingId)),
274
    mMoney(0),
275
    mAmountItems(0),
276
    mMaxItems(0),
277



24
    mAdvanced(true)
278
{
279
1
    init();
280
1
}
281
282
4
void BuyDialog::init()
283
{
284
20
    setWindowName("Buy");
285
4
    setResizable(true);
286
4
    setCloseButton(true);
287
4
    setStickyButtonLock(true);
288
4
    setMinWidth(260);
289
4
    setMinHeight(220);
290
4
    setDefaultSize(260, 230, ImagePosition::CENTER, 0, 0);
291
292
#ifdef TMWA_SUPPORT
293
    // reset advance flag for personal shops
294

6
    if (mAdvanced &&
295
2
        mNpcId == fromInt(Nick, BeingId))
296
    {
297
        mAdvanced = false;
298
    }
299
#endif  // TMWA_SUPPORT
300
301
4
    if (setupWindow != nullptr)
302
        setupWindow->registerWindowForReset(this);
303
304
4
    mShopItems = new ShopItems(false,
305
4
        mCurrency);
306
307
4
    CREATEWIDGETV(mShopItemList, ShopListBox, this,
308
4
        mShopItems, mShopItems, ShopListBoxType::Unknown);
309
8
    mScrollArea = new ScrollArea(this, mShopItemList,
310

16
        fromBool(getOptionBool("showbackground", false), Opaque),
311

20
        "buy_background.xml");
312
4
    mScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
313
314
4
    mSlider = new Slider(this, 1.0, 1.0);
315
12
    mQuantityLabel = new Label(this, strprintf(
316

4
        "%d / %d", mAmountItems, mMaxItems));
317
8
    mQuantityLabel->setAlignment(Graphics::CENTER);
318
12
    mMoneyLabel = new Label(this, strprintf(
319
        // TRANSLATORS: buy dialog label
320

8
        _("Price: %s / Total: %s"), "", ""));
321
322
4
    mAmountField = new IntTextField(this, 1, 1, 123, Enable_true, 0);
323
20
    mAmountField->setActionEventId("amount");
324
4
    mAmountField->addActionListener(this);
325
8
    mAmountField->setSendAlwaysEvents(true);
326
8
    mAmountField->setEnabled(false);
327
328
    // TRANSLATORS: buy dialog label
329

16
    mAmountLabel = new Label(this, _("Amount:"));
330
4
    mAmountLabel->adjustSize();
331
332
    // TRANSLATORS: This is a narrow symbol used to denote 'increasing'.
333
    // You may change this symbol if your language uses another.
334

28
    mIncreaseButton = new Button(this, _("+"), "inc", BUTTON_SKIN, this);
335
    // TRANSLATORS: This is a narrow symbol used to denote 'decreasing'.
336
    // You may change this symbol if your language uses another.
337

28
    mDecreaseButton = new Button(this, _("-"), "dec", BUTTON_SKIN, this);
338
8
    mBuyButton = new Button(this, mNpcId == fromInt(Items, BeingId)
339
        // TRANSLATORS: buy dialog button
340
3
        ? _("Create") : (mAdvanced ? _("Add") : _("Buy")),
341
        "buy",
342
        BUTTON_SKIN,
343


31
        this);
344
4
    if (mAdvanced)
345
    {
346
2
        mConfirmButton = new Button(this,
347
            // TRANSLATORS: buy dialog button
348
2
            _("Buy"),
349
            "confirm",
350
            BUTTON_SKIN,
351

14
            this);
352
2
        mConfirmButton->setEnabled(false);
353
    }
354
    else
355
    {
356
2
        mConfirmButton = nullptr;
357
    }
358
    // TRANSLATORS: buy dialog button
359

28
    mQuitButton = new Button(this, _("Quit"), "quit", BUTTON_SKIN, this);
360
    // TRANSLATORS: buy dialog button
361

28
    mAddMaxButton = new Button(this, _("Max"), "max", BUTTON_SKIN, this);
362
363
4
    mDecreaseButton->adjustSize();
364
8
    mDecreaseButton->setWidth(mIncreaseButton->getWidth());
365
366
8
    mIncreaseButton->setEnabled(false);
367
8
    mDecreaseButton->setEnabled(false);
368
8
    mBuyButton->setEnabled(false);
369
8
    mSlider->setEnabled(false);
370
371
20
    mSlider->setActionEventId("slider");
372
4
    mSlider->addActionListener(this);
373
374
8
    mShopItemList->setDistributeMousePressed(false);
375
20
    mShopItemList->setActionEventId("buy");
376
4
    mShopItemList->addActionListener(this);
377
4
    mShopItemList->addSelectionListener(this);
378
379
4
    mFilterTextField->setWidth(100);
380
381
4
    ContainerPlacer placer = getPlacer(0, 0);
382
8
    placer(0, 0, mScrollArea, 9, 5).setPadding(3);
383
4
    placer(0, 5, mDecreaseButton, 1, 1);
384
4
    placer(1, 5, mSlider, 4, 1);
385
4
    placer(5, 5, mIncreaseButton, 1, 1);
386
4
    placer(6, 5, mQuantityLabel, 2, 1);
387
4
    placer(8, 5, mAddMaxButton, 1, 1);
388
4
    placer(0, 6, mAmountLabel, 2, 1);
389
4
    placer(2, 6, mAmountField, 2, 1);
390
4
    placer(0, 7, mMoneyLabel, 8, 1);
391
4
    if (mSortDropDown != nullptr)
392
    {
393
3
        placer(0, 8, mSortDropDown, 2, 1);
394
    }
395
    else
396
    {
397
        // TRANSLATORS: buy dialog label
398

4
        mFilterLabel = new Label(this, _("Filter:"));
399
1
        mFilterLabel->adjustSize();
400
1
        placer(0, 8, mFilterLabel, 2, 1);
401
    }
402
4
    placer(2, 8, mFilterTextField, 2, 1);
403
4
    if (mAdvanced)
404
    {
405
2
        placer(6, 8, mBuyButton, 1, 1);
406
2
        placer(7, 8, mConfirmButton, 1, 1);
407
    }
408
    else
409
    {
410
2
        placer(7, 8, mBuyButton, 1, 1);
411
    }
412
4
    placer(8, 8, mQuitButton, 1, 1);
413
414
4
    Layout &layout = getLayout();
415
4
    layout.setRowHeight(0, LayoutType::SET);
416
417
4
    center();
418
4
    loadWindowState();
419
8
    enableVisibleSound(true);
420
421
8
    instances.push_back(this);
422
4
    setVisible(Visible_true);
423
424
4
    if (mSortDropDown != nullptr)
425

12
        mSortDropDown->setSelected(config.getIntValue("buySortOrder"));
426
4
}
427
428
28
BuyDialog::~BuyDialog()
429
{
430
4
    delete2(mShopItems)
431
8
    delete2(mSortModel)
432
4
    instances.remove(this);
433
4
    if (buySellHandler != nullptr)
434
        buySellHandler->cleanDialogReference(this);
435
8
}
436
437
void BuyDialog::setMoney(const int amount)
438
{
439
    mMoney = amount;
440
    mShopItemList->setPlayersMoney(amount);
441
442
    updateButtonsAndLabels();
443
}
444
445
void BuyDialog::reset()
446
{
447
    mShopItems->clear();
448
    mShopItemList->adjustSize();
449
450
    // Reset previous selected items to prevent failing asserts
451
    mShopItemList->setSelected(-1);
452
    mSlider->setValue(0);
453
454
    setMoney(0);
455
}
456
457
ShopItem *BuyDialog::addItem(const int id,
458
                             const ItemTypeT type,
459
                             const ItemColor color,
460
                             const int amount,
461
                             const int price)
462
{
463
    ShopItem *const item = mShopItems->addItem(id,
464
        type,
465
        color,
466
        amount,
467
        price);
468
    mShopItemList->adjustSize();
469
    return item;
470
}
471
472
void BuyDialog::sort()
473
{
474
    if ((mSortDropDown != nullptr) && (mShopItems != nullptr))
475
    {
476
        STD_VECTOR<ShopItem*> &items = mShopItems->items();
477
        switch (mSortDropDown->getSelected())
478
        {
479
            case 1:
480
                std::sort(items.begin(), items.end(), itemPriceBuySorter);
481
            break;
482
            case 2:
483
                std::sort(items.begin(), items.end(), itemNameBuySorter);
484
                break;
485
            case 3:
486
                std::sort(items.begin(), items.end(), itemIdBuySorter);
487
                break;
488
            case 4:
489
                std::sort(items.begin(), items.end(), itemWeightBuySorter);
490
                break;
491
            case 5:
492
                std::sort(items.begin(), items.end(), itemAmountBuySorter);
493
                break;
494
            case 6:
495
                std::sort(items.begin(), items.end(), itemTypeBuySorter);
496
                break;
497
            case 0:
498
            default:
499
                break;
500
        }
501
    }
502
}
503
504
void BuyDialog::close()
505
{
506
    switch (toInt(mNpcId, int))
507
    {
508
#ifdef TMWA_SUPPORT
509
        case Nick:
510
#endif  // TMWA_SUPPORT
511
        case Items:
512
            break;
513
        case Market:
514
            marketHandler->close();
515
            break;
516
        case Cash:
517
            cashShopHandler->close();
518
            break;
519
        case Vending:
520
            vendingHandler->close();
521
            break;
522
        default:
523
            buySellHandler->close();
524
            break;
525
    }
526
    Window::close();
527
}
528
529
void BuyDialog::action(const ActionEvent &event)
530
{
531
    const std::string &eventId = event.getId();
532
    if (eventId == "quit")
533
    {
534
        close();
535
        return;
536
    }
537
    else if (eventId == "sort")
538
    {
539
        sort();
540
        if (mSortDropDown != nullptr)
541
            config.setValue("buySortOrder", mSortDropDown->getSelected());
542
        return;
543
    }
544
    else if (eventId == "namefilter")
545
    {
546
        applyNameFilter(mFilterTextField->getText());
547
    }
548
549
    const int selectedItem = mShopItemList->getSelected();
550
551
    // The following actions require a valid selection
552
    if (selectedItem < 0 || selectedItem >= mShopItems->getNumberOfElements())
553
        return;
554
555
    if (eventId == "slider")
556
    {
557
        mAmountItems = CAST_S32(mSlider->getValue());
558
        mAmountField->setValue(mAmountItems);
559
        updateButtonsAndLabels();
560
    }
561
    else if (eventId == "inc" && mAmountItems < mMaxItems)
562
    {
563
        mAmountItems++;
564
        mSlider->setValue(mAmountItems);
565
        mAmountField->setValue(mAmountItems);
566
        updateButtonsAndLabels();
567
    }
568
    else if (eventId == "dec" && mAmountItems > 1)
569
    {
570
        mAmountItems--;
571
        mSlider->setValue(mAmountItems);
572
        mAmountField->setValue(mAmountItems);
573
        updateButtonsAndLabels();
574
    }
575
    else if (eventId == "max")
576
    {
577
        mAmountItems = mMaxItems;
578
        mSlider->setValue(mAmountItems);
579
        mAmountField->setValue(mAmountItems);
580
        updateButtonsAndLabels();
581
    }
582
    else if (eventId == "amount")
583
    {
584
        mAmountItems = mAmountField->getValue();
585
        mSlider->setValue(mAmountItems);
586
        updateButtonsAndLabels();
587
    }
588
    else if (eventId == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems)
589
    {
590
        ShopItem *const item = mShopItems->at(selectedItem);
591
        if (item == nullptr)
592
            return;
593
        if (mNpcId == fromInt(Items, BeingId))
594
        {
595
            adminHandler->createItems(item->getId(),
596
                item->getColor(),
597
                mAmountItems);
598
        }
599
#ifdef TMWA_SUPPORT
600
        else if (mNpcId == fromInt(Nick, BeingId))
601
        {
602
            if (tradeWindow != nullptr)
603
            {
604
                buySellHandler->sendBuyRequest(mNick,
605
                    item, mAmountItems);
606
                tradeWindow->addAutoMoney(mNick,
607
                    item->getPrice() * mAmountItems);
608
            }
609
        }
610
#endif  // TMWA_SUPPORT
611
        else if (mNpcId == fromInt(Vending, BeingId))
612
        {
613
            item->increaseUsedQuantity(mAmountItems);
614
            item->update();
615
            if (mConfirmButton != nullptr)
616
                mConfirmButton->setEnabled(true);
617
        }
618
#ifdef TMWA_SUPPORT
619
        else if (mNpcId != fromInt(Nick, BeingId))
620
#else
621
        else
622
#endif  // TMWA_SUPPORT
623
        {
624
            if (mAdvanced)
625
            {
626
                item->increaseUsedQuantity(mAmountItems);
627
                item->update();
628
                if (mConfirmButton != nullptr)
629
                    mConfirmButton->setEnabled(true);
630
            }
631
            else if (mNpcId == fromInt(Market, BeingId))
632
            {
633
                marketHandler->buyItem(item->getId(),
634
                    item->getType(),
635
                    item->getColor(),
636
                    mAmountItems);
637
                item->increaseQuantity(-mAmountItems);
638
                item->update();
639
            }
640
            else if (mNpcId == fromInt(Cash, BeingId))
641
            {
642
                cashShopHandler->buyItem(item->getPrice(),
643
                    item->getId(),
644
                    item->getColor(),
645
                    mAmountItems);
646
            }
647
            else
648
            {
649
                npcHandler->buyItem(mNpcId,
650
                    item->getId(),
651
                    item->getColor(),
652
                    mAmountItems);
653
            }
654
655
            updateSlider(selectedItem);
656
        }
657
    }
658
    else if (eventId == "confirm")
659
    {
660
        STD_VECTOR<ShopItem*> &items = mShopItems->allItems();
661
662
        if (mNpcId == fromInt(Market, BeingId))
663
        {
664
            marketHandler->buyItems(items);
665
        }
666
        else if (mNpcId == fromInt(Vending, BeingId))
667
        {
668
            const Being *const being = actorManager->findBeingByName(
669
                mNick,
670
                ActorType::Player);
671
            if (being != nullptr)
672
            {
673
                vendingHandler->buyItems(being,
674
                    items);
675
            }
676
        }
677
        else if (mNpcId == fromInt(Cash, BeingId))
678
        {
679
            cashShopHandler->buyItems(0, items);
680
        }
681
        else
682
        {
683
            npcHandler->buyItems(items);
684
        }
685
        close();
686
    }
687
}
688
689
void BuyDialog::updateSlider(const int selectedItem)
690
{
691
    // Update money and adjust the max number of items
692
    // that can be bought
693
    mMaxItems -= mAmountItems;
694
    const ShopItem *const item = mShopItems->at(selectedItem);
695
    if (item != nullptr)
696
        setMoney(mMoney - mAmountItems * item->getPrice());
697
    else
698
        setMoney(mMoney);
699
700
    // Reset selection
701
    mAmountItems = 1;
702
    mSlider->setScale(1, mMaxItems);
703
    mSlider->setValue(1);
704
}
705
706
void BuyDialog::valueChanged(const SelectionEvent &event A_UNUSED)
707
{
708
    // Reset amount of items and update labels
709
    mAmountItems = 1;
710
    mSlider->setValue(1);
711
712
    updateButtonsAndLabels();
713
    mSlider->setScale(1, mMaxItems);
714
    mAmountField->setRange(1, mMaxItems);
715
    mAmountField->setValue(1);
716
}
717
718
void BuyDialog::updateButtonsAndLabels()
719
{
720
    const int selectedItem = mShopItemList->getSelected();
721
    int price = 0;
722
723
    if (selectedItem > -1)
724
    {
725
        const ShopItem *const item = mShopItems->at(selectedItem);
726
        if (item != nullptr)
727
        {
728
            const int itemPrice = item->getPrice();
729
730
            // Calculate how many the player can afford
731
            if (mNpcId == fromInt(Items, BeingId))
732
                mMaxItems = 100;
733
            else if (itemPrice != 0)
734
                mMaxItems = mMoney / itemPrice;
735
            else
736
                mMaxItems = 1;
737
738
            if (mNpcId == fromInt(Market, BeingId))
739
            {
740
                if (mMaxItems > item->getQuantity())
741
                    mMaxItems = item->getQuantity();
742
            }
743
            else if (item->getQuantity() > 0 &&
744
                     mMaxItems > item->getQuantity())
745
            {
746
                mMaxItems = item->getQuantity();
747
            }
748
749
            if (mAmountItems > mMaxItems)
750
                mAmountItems = mMaxItems;
751
752
            price = mAmountItems * itemPrice;
753
        }
754
    }
755
    else
756
    {
757
        mMaxItems = 0;
758
        mAmountItems = 0;
759
    }
760
761
    mIncreaseButton->setEnabled(mAmountItems < mMaxItems);
762
    mDecreaseButton->setEnabled(mAmountItems > 1);
763
    mBuyButton->setEnabled(mAmountItems > 0);
764
    mSlider->setEnabled(mMaxItems > 1);
765
    mAmountField->setEnabled(mAmountItems > 0);
766
767
    mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems));
768
    // TRANSLATORS: buy dialog label
769
    mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"),
770
        UnitsDb::formatCurrency(mCurrency, price).c_str(),
771
        UnitsDb::formatCurrency(mCurrency, mMoney - price).c_str()));
772
}
773
774
4
void BuyDialog::setVisible(Visible visible)
775
{
776
4
    Window::setVisible(visible);
777
778

4
    if (visible == Visible_true && (mShopItemList != nullptr))
779
4
        mShopItemList->requestFocus();
780
    else
781
        scheduleDelete();
782
4
}
783
784
void BuyDialog::closeAll()
785
{
786
    FOR_EACH (DialogList::const_iterator, it, instances)
787
    {
788
        if (*it != nullptr)
789
            (*it)->close();
790
    }
791
}
792
793
void BuyDialog::applyNameFilter(const std::string &filter)
794
{
795
    STD_VECTOR<ShopItem*> &items = mShopItems->allItems();
796
    std::string filterStr = filter;
797
    toLower(filterStr);
798
    FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
799
    {
800
        ShopItem *const item = *it;
801
        if (item == nullptr)
802
            continue;
803
        std::string name = item->getName();
804
        toLower(name);
805
        if (name.find(filterStr) != std::string::npos)
806
            item->setVisible(true);
807
        else
808
            item->setVisible(false);
809
    }
810
    mShopItems->updateList();
811

3
}