GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/equipmentwindow.cpp Lines: 129 447 28.9 %
Date: 2017-11-29 Branches: 91 426 21.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-2017  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/equipmentwindow.h"
24
25
#include "configuration.h"
26
#include "dragdrop.h"
27
28
#include "being/localplayer.h"
29
#include "being/playerinfo.h"
30
31
#include "gui/fonts/font.h"
32
33
#include "gui/popups/popupmenu.h"
34
#include "gui/popups/itempopup.h"
35
36
#include "gui/windows/setupwindow.h"
37
38
#include "gui/widgets/button.h"
39
#include "gui/widgets/equipmentbox.h"
40
#include "gui/widgets/equipmentpage.h"
41
#include "gui/widgets/playerbox.h"
42
#include "gui/widgets/tabstrip.h"
43
44
#include "render/vertexes/imagecollection.h"
45
46
#include "resources/imageset.h"
47
48
#include "utils/checkutils.h"
49
#include "utils/delete2.h"
50
#include "utils/dtor.h"
51
#include "utils/foreach.h"
52
#include "utils/gettext.h"
53
54
#include "net/inventoryhandler.h"
55
56
#include "debug.h"
57
58
EquipmentWindow *equipmentWindow = nullptr;
59
EquipmentWindow *beingEquipmentWindow = nullptr;
60
static const int BOX_COUNT = 27;
61
2
StringIntMap EquipmentWindow::mSlotNames;
62
63
2
EquipmentWindow::EquipmentWindow(Equipment *const equipment,
64
                                 Being *const being,
65
2
                                 const bool foring) :
66
    // TRANSLATORS: equipment window name
67
2
    Window(_("Equipment"), Modal_false, nullptr, "equipment.xml"),
68
    ActionListener(),
69
    mEquipment(equipment),
70
    mPlayerBox(new PlayerBox(this,
71
        "equipment_playerbox.xml",
72

2
        "equipment_selectedplayerbox.xml")),
73
    // TRANSLATORS: equipment window button
74

4
    mUnequip(new Button(this, _("Unequip"), "unequip", this)),
75
    mImageSet(nullptr),
76
    mBeing(being),
77
    mSlotBackground(),
78
    mSlotHighlightedBackground(),
79

2
    mVertexes(new ImageCollection),
80
    mPages(),
81
    mTabs(nullptr),
82
4
    mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT)),
83
4
    mBorderColor(getThemeColor(ThemeColorId::BORDER)),
84
4
    mLabelsColor(getThemeColor(ThemeColorId::LABEL)),
85
4
    mLabelsColor2(getThemeColor(ThemeColorId::LABEL_OUTLINE)),
86
    mSelected(-1),
87

8
    mItemPadding(getOption("itemPadding")),
88

8
    mBoxSize(getOption("boxSize")),
89

8
    mButtonPadding(getOption("buttonPadding", 5)),
90
    mMinX(180),
91
    mMinY(345),
92
    mMaxX(0),
93
    mMaxY(0),
94
    mYPadding(0),
95
    mSelectedTab(0),
96
    mForing(foring),
97



64
    mHaveDefaultPage(false)
98
{
99

8
    const int size = config.getIntValue("fontSize")
100

8
        + getOption("tabHeightAdjust", 16);
101

8
    mTabs = new TabStrip(this, "equipment", size);
102
2
    mTabs->addActionListener(this);
103
10
    mTabs->setActionEventId("tab_");
104
4
    mTabs->setSelectable(false);
105
106

10
    mYPadding = mTabs->getHeight() + getOption("tabPadding", 2);
107
108
2
    if (setupWindow != nullptr)
109
        setupWindow->registerWindowForReset(this);
110
111
2
    if (mBoxSize == 0)
112
        mBoxSize = 36;
113
114
    // Control that shows the Player
115
4
    mPlayerBox->setDimension(Rect(50, 80 + mYPadding, 74, 168));
116
4
    mPlayerBox->setPlayer(being);
117
4
    mPlayerBox->setSelectable(false);
118
119
2
    if (foring)
120
        setWindowName("Being equipment");
121
    else
122
10
        setWindowName("Equipment");
123
124
2
    setCloseButton(true);
125
4
    setSaveVisible(true);
126
2
    setStickyButtonLock(true);
127
128
2
    fillBoxes();
129
2
    recalcSize();
130
2
    updatePage();
131
2
    loadWindowState();
132
2
}
133
134
2
void EquipmentWindow::postInit()
135
{
136
2
    Window::postInit();
137
4
    const Rect &area = getChildrenArea();
138
6
    mUnequip->setPosition(area.width  - mUnequip->getWidth() - mButtonPadding,
139
4
        area.height - mUnequip->getHeight() - mButtonPadding);
140
4
    mUnequip->setEnabled(false);
141
142
2
    ImageRect rect;
143

14
    theme->loadRect(rect, "equipment_background.xml", "", 0, 1);
144
2
    mSlotBackground = rect.grid[0];
145
2
    mSlotHighlightedBackground = rect.grid[1];
146
2
    add(mTabs);
147
2
    add(mPlayerBox);
148
2
    add(mUnequip);
149
4
    enableVisibleSound(true);
150
10
    mPlayerBox->setActionEventId("playerbox");
151
2
    mPlayerBox->addActionListener(this);
152
2
}
153
154
10
EquipmentWindow::~EquipmentWindow()
155
{
156
2
    if (this == beingEquipmentWindow)
157
    {
158
        if (mEquipment != nullptr)
159
            delete mEquipment->getBackend();
160
        delete2(mEquipment)
161
    }
162
12
    FOR_EACH (STD_VECTOR<EquipmentPage*>::iterator, it, mPages)
163
    {
164
4
        STD_VECTOR<EquipmentBox*> &boxes = (*it)->boxes;
165
4
        delete_all(boxes);
166
4
        boxes.clear();
167
8
        delete *it;
168
    }
169
2
    if (mImageSet != nullptr)
170
    {
171
2
        mImageSet->decRef();
172
2
        mImageSet = nullptr;
173
    }
174
2
    if (mSlotBackground != nullptr)
175
2
        mSlotBackground->decRef();
176
2
    if (mSlotHighlightedBackground != nullptr)
177
2
        mSlotHighlightedBackground->decRef();
178
2
    delete2(mVertexes);
179
4
}
180
181
void EquipmentWindow::draw(Graphics *const graphics)
182
{
183
    BLOCK_START("EquipmentWindow::draw")
184
    // Draw window graphics
185
    Window::draw(graphics);
186
187
    int i = 0;
188
    Font *const font = getFont();
189
    const int fontHeight = font->getHeight();
190
    const STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
191
192
    if (mLastRedraw)
193
    {
194
        mVertexes->clear();
195
        FOR_EACH (STD_VECTOR<EquipmentBox*>::const_iterator, it, boxes)
196
        {
197
            const EquipmentBox *const box = *it;
198
            if (box == nullptr)
199
            {
200
                i ++;
201
                continue;
202
            }
203
            if (i == mSelected)
204
            {
205
                graphics->calcTileCollection(mVertexes,
206
                    mSlotHighlightedBackground,
207
                    box->x, box->y);
208
            }
209
            else
210
            {
211
                graphics->calcTileCollection(mVertexes,
212
                    mSlotBackground,
213
                    box->x, box->y);
214
            }
215
            i ++;
216
        }
217
        graphics->finalize(mVertexes);
218
    }
219
    graphics->drawTileCollection(mVertexes);
220
221
    if (mEquipment == nullptr)
222
    {
223
        BLOCK_END("EquipmentWindow::draw")
224
        return;
225
    }
226
227
    i = 0;
228
    const int projSlot = inventoryHandler->getProjectileSlot();
229
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
230
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
231
    {
232
        const EquipmentBox *const box = *it;
233
        if (box == nullptr)
234
            continue;
235
        const Item *const item = mEquipment->getEquipment(i);
236
        if (item != nullptr)
237
        {
238
            // Draw Item.
239
            Image *const image = item->getImage();
240
            if (image != nullptr)
241
            {
242
                image->setAlpha(1.0F);  // Ensure the image is drawn
243
                                        // with maximum opacity
244
                graphics->drawImage(image, box->x + mItemPadding,
245
                    box->y + mItemPadding);
246
                if (i == projSlot)
247
                {
248
                    const std::string str = toString(item->getQuantity());
249
                    font->drawString(graphics,
250
                        mLabelsColor,
251
                        mLabelsColor2,
252
                        str,
253
                        box->x + (mBoxSize - font->getWidth(str)) / 2,
254
                        box->y - fontHeight);
255
                }
256
            }
257
        }
258
        else if (box->image != nullptr)
259
        {
260
            graphics->drawImage(box->image,
261
                box->x + mItemPadding,
262
                box->y + mItemPadding);
263
        }
264
    }
265
    BLOCK_END("EquipmentWindow::draw")
266
}
267
268
void EquipmentWindow::safeDraw(Graphics *const graphics)
269
{
270
    BLOCK_START("EquipmentWindow::draw")
271
    // Draw window graphics
272
    Window::safeDraw(graphics);
273
274
    int i = 0;
275
    Font *const font = getFont();
276
    const int fontHeight = font->getHeight();
277
    const STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
278
279
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
280
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
281
    {
282
        const EquipmentBox *const box = *it;
283
        if (box == nullptr)
284
            continue;
285
        if (i == mSelected)
286
        {
287
            graphics->drawImage(mSlotHighlightedBackground,
288
                box->x, box->y);
289
        }
290
        else
291
        {
292
            graphics->drawImage(mSlotBackground, box->x, box->y);
293
        }
294
    }
295
296
    if (mEquipment == nullptr)
297
    {
298
        BLOCK_END("EquipmentWindow::draw")
299
        return;
300
    }
301
302
    i = 0;
303
    const int projSlot = inventoryHandler->getProjectileSlot();
304
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
305
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
306
    {
307
        const EquipmentBox *const box = *it;
308
        if (box == nullptr)
309
            continue;
310
        const Item *const item = mEquipment->getEquipment(i);
311
        if (item != nullptr)
312
        {
313
            // Draw Item.
314
            Image *const image = item->getImage();
315
            if (image != nullptr)
316
            {
317
                image->setAlpha(1.0F);  // Ensure the image is drawn
318
                                        // with maximum opacity
319
                graphics->drawImage(image, box->x + mItemPadding,
320
                    box->y + mItemPadding);
321
                if (i == projSlot)
322
                {
323
                    const std::string str = toString(item->getQuantity());
324
                    font->drawString(graphics,
325
                        mLabelsColor,
326
                        mLabelsColor2,
327
                        str,
328
                        box->x + (mBoxSize - font->getWidth(str)) / 2,
329
                        box->y - fontHeight);
330
                }
331
            }
332
        }
333
        else if (box->image != nullptr)
334
        {
335
            graphics->drawImage(box->image,
336
                box->x + mItemPadding,
337
                box->y + mItemPadding);
338
        }
339
    }
340
    BLOCK_END("EquipmentWindow::draw")
341
}
342
343
void EquipmentWindow::action(const ActionEvent &event)
344
{
345
    const std::string &eventId = event.getId();
346
    if (eventId == "unequip")
347
    {
348
        if ((mEquipment == nullptr) || mSelected == -1)
349
            return;
350
351
        const Item *const item = mEquipment->getEquipment(mSelected);
352
        PlayerInfo::unequipItem(item, Sfx_true);
353
        setSelected(-1);
354
    }
355
    else if (eventId.find("tab_") == 0u)
356
    {
357
        Button *const button = dynamic_cast<Button*>(event.getSource());
358
        if (button == nullptr)
359
            return;
360
        mSelectedTab = button->getTag();
361
        updatePage();
362
    }
363
    else if (eventId == "playerbox")
364
    {
365
        const DragDropSourceT src = dragDrop.getSource();
366
        if (dragDrop.isEmpty() || (src != DragDropSource::Inventory
367
            && src != DragDropSource::Equipment))
368
        {
369
            return;
370
        }
371
        Inventory *const inventory = localPlayer != nullptr
372
            ? PlayerInfo::getInventory() : nullptr;
373
        if (inventory == nullptr)
374
            return;
375
        Item *const item = inventory->findItem(dragDrop.getItem(),
376
            dragDrop.getItemColor());
377
        if (item == nullptr)
378
            return;
379
380
        if (dragDrop.getSource() == DragDropSource::Inventory)
381
        {
382
            if (item->isEquipment() == Equipm_true)
383
            {
384
                if (item->isEquipped() == Equipped_false)
385
                    PlayerInfo::equipItem(item, Sfx_true);
386
            }
387
        }
388
    }
389
}
390
391
2
void EquipmentWindow::updatePage()
392
{
393
4
    EquipmentPage *const page = mPages[mSelectedTab];
394
2
    const Visible visible = fromBool(page->showPlayerBox, Visible);
395
2
    mPlayerBox->setVisible(visible);
396
2
    if (visible == Visible_true)
397
    {
398
4
        mPlayerBox->setDimension(Rect(page->x, page->y,
399
            page->width, page->height));
400
    }
401
2
    mRedraw = true;
402
2
}
403
404
const Item *EquipmentWindow::getItem(const int x, const int y) const
405
{
406
    if (mEquipment == nullptr)
407
        return nullptr;
408
409
    int i = 0;
410
411
    STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
412
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
413
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
414
    {
415
        const EquipmentBox *const box = *it;
416
        if (box == nullptr)
417
            continue;
418
        const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
419
420
        if (tRect.isPointInRect(x, y))
421
            return mEquipment->getEquipment(i);
422
    }
423
    return nullptr;
424
}
425
426
void EquipmentWindow::mousePressed(MouseEvent& event)
427
{
428
    if (mEquipment == nullptr)
429
    {
430
        Window::mousePressed(event);
431
        return;
432
    }
433
434
    const int x = event.getX();
435
    const int y = event.getY();
436
437
    if (event.getButton() == MouseButton::LEFT)
438
    {
439
        if (mForing)
440
        {
441
            Window::mousePressed(event);
442
            return;
443
        }
444
        // Checks if any of the presses were in the equip boxes.
445
        int i = 0;
446
447
        bool inBox(false);
448
449
        STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
450
        for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
451
             it_end = boxes.end(); it != it_end; ++ it, ++ i)
452
        {
453
            const EquipmentBox *const box = *it;
454
            if (box == nullptr)
455
                continue;
456
            const Item *const item = mEquipment->getEquipment(i);
457
            const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
458
459
            if (tRect.isPointInRect(x, y))
460
            {
461
                inBox = true;
462
                if (item != nullptr)
463
                {
464
                    event.consume();
465
                    setSelected(i);
466
                    dragDrop.dragItem(item, DragDropSource::Equipment);
467
                    return;
468
                }
469
            }
470
            if (inBox)
471
                return;
472
        }
473
    }
474
    else if (event.getButton() == MouseButton::RIGHT)
475
    {
476
        if (const Item *const item = getItem(x, y))
477
        {
478
            if (itemPopup != nullptr)
479
                itemPopup->setVisible(Visible_false);
480
481
            /* Convert relative to the window coordinates to absolute screen
482
             * coordinates.
483
             */
484
            const int mx = x + getX();
485
            const int my = y + getY();
486
            if (popupMenu != nullptr)
487
            {
488
                event.consume();
489
                if (mForing)
490
                {
491
                    popupMenu->showUndressPopup(mx, my, mBeing, item);
492
                }
493
                else
494
                {
495
                    popupMenu->showPopup(this, mx, my, item,
496
                        InventoryType::Inventory);
497
                }
498
                return;
499
            }
500
        }
501
    }
502
    Window::mousePressed(event);
503
}
504
505
void EquipmentWindow::mouseReleased(MouseEvent &event)
506
{
507
    Window::mouseReleased(event);
508
    const DragDropSourceT src = dragDrop.getSource();
509
    if (dragDrop.isEmpty() || (src != DragDropSource::Inventory
510
        && src != DragDropSource::Equipment))
511
    {
512
        return;
513
    }
514
    Inventory *const inventory = localPlayer != nullptr
515
        ? PlayerInfo::getInventory() : nullptr;
516
    if (inventory == nullptr)
517
        return;
518
519
    Item *const item = inventory->findItem(dragDrop.getItem(),
520
        dragDrop.getItemColor());
521
    if (item == nullptr)
522
        return;
523
524
    if (dragDrop.getSource() == DragDropSource::Inventory)
525
    {
526
        if (item->isEquipment() == Equipm_true)
527
        {
528
            if (item->isEquipped() == Equipped_false)
529
                PlayerInfo::equipItem(item, Sfx_true);
530
        }
531
    }
532
    else if (dragDrop.getSource() == DragDropSource::Equipment)
533
    {
534
        if (item->isEquipment() == Equipm_true)
535
        {
536
            const int x = event.getX();
537
            const int y = event.getY();
538
            STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
539
            for (STD_VECTOR<EquipmentBox*>::const_iterator
540
                 it = boxes.begin(), it_end = boxes.end();
541
                 it != it_end; ++ it)
542
            {
543
                const EquipmentBox *const box = *it;
544
                if (box == nullptr)
545
                    continue;
546
                const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
547
548
                if (tRect.isPointInRect(x, y))
549
                    return;
550
            }
551
552
            if (item->isEquipped() == Equipped_true)
553
                PlayerInfo::unequipItem(item, Sfx_true);
554
        }
555
    }
556
    dragDrop.clear();
557
    dragDrop.deselect();
558
}
559
560
// Show ItemTooltip
561
void EquipmentWindow::mouseMoved(MouseEvent &event)
562
{
563
    Window::mouseMoved(event);
564
565
    if (itemPopup == nullptr)
566
        return;
567
568
    const int x = event.getX();
569
    const int y = event.getY();
570
571
    const Item *const item = getItem(x, y);
572
573
    if (item != nullptr)
574
    {
575
        itemPopup->setItem(item, false);
576
        itemPopup->position(x + getX(), y + getY());
577
    }
578
    else
579
    {
580
        itemPopup->setVisible(Visible_false);
581
    }
582
}
583
584
// Hide ItemTooltip
585
void EquipmentWindow::mouseExited(MouseEvent &event A_UNUSED)
586
{
587
    if (itemPopup != nullptr)
588
        itemPopup->setVisible(Visible_false);
589
}
590
591
void EquipmentWindow::setSelected(const int index)
592
{
593
    mSelected = index;
594
    mRedraw = true;
595
    if (mUnequip != nullptr)
596
        mUnequip->setEnabled(mSelected != -1);
597
    if (itemPopup != nullptr)
598
        itemPopup->setVisible(Visible_false);
599
}
600
601
void EquipmentWindow::setBeing(Being *const being)
602
{
603
    mPlayerBox->setPlayer(being);
604
    mBeing = being;
605
    if (mEquipment != nullptr)
606
        delete mEquipment->getBackend();
607
    delete mEquipment;
608
    if (being == nullptr)
609
    {
610
        mEquipment = nullptr;
611
        return;
612
    }
613
    mEquipment = being->getEquipment();
614
}
615
616
void EquipmentWindow::updateBeing(Being *const being)
617
{
618
    if (being == mBeing)
619
        setBeing(being);
620
}
621
622
void EquipmentWindow::resetBeing(const Being *const being)
623
{
624
    if (being == mBeing)
625
        setBeing(nullptr);
626
}
627
628
2
void EquipmentWindow::fillBoxes()
629
{
630
    XML::Document *const doc = new XML::Document(
631

10
        paths.getStringValue("equipmentWindowFile"),
632
        UseVirtFs_true,
633

2
        SkipError_false);
634
2
    XmlNodeConstPtr root = doc->rootNode();
635
2
    if (root == nullptr)
636
    {
637
        delete doc;
638
        fillDefault();
639
        return;
640
    }
641
642
2
    if (mImageSet != nullptr)
643
        mImageSet->decRef();
644
645

10
    mImageSet = Theme::getImageSetFromTheme(XML::getProperty(
646
        root, "image", "equipmentbox.png"), 32, 32);
647
648
12
    for_each_xml_child_node(node, root)
649
    {
650
10
        if (xmlNameEqual(node, "page"))
651
        {
652
4
            loadPage(node);
653
        }
654
    }
655
2
    delete doc;
656

4
    if (reportTrue(mPages.empty()))
657
        fillDefault();
658
}
659
660
void EquipmentWindow::addDefaultPage()
661
{
662
    if (!mHaveDefaultPage)
663
    {
664
        mHaveDefaultPage = true;
665
        // TRANSLATORS: equipment window tab
666
        addPage(_("default"));
667
    }
668
}
669
670
4
void EquipmentWindow::loadPage(XmlNodeConstPtr node)
671
{
672
4
    if (node == nullptr)
673
        return;
674
    // TRANSLATORS: unknown equipment page name
675

16
    const std::string &name = XML::langProperty(node, "name", _("Unknown"));
676
4
    const int page = addPage(name);
677
160
    for_each_xml_child_node(childNode, node)
678
    {
679

156
        if (xmlNameEqual(childNode, "playerbox"))
680
2
            loadPlayerBox(childNode, page);
681

154
        else if (xmlNameEqual(childNode, "slot"))
682
74
            loadSlot(childNode, mImageSet, page);
683
    }
684
}
685
686
2
void EquipmentWindow::loadPlayerBox(XmlNodeConstPtr playerBoxNode,
687
                                    const int page)
688
{
689
4
    EquipmentPage *const data = mPages[page];
690
2
    data->x = XML::getProperty(playerBoxNode, "x", 50);
691
2
    data->y = XML::getProperty(playerBoxNode, "y", 80) + mYPadding;
692
2
    data->width = XML::getProperty(playerBoxNode, "width", 74);
693
2
    data->height = XML::getProperty(playerBoxNode, "height", 168);
694
2
}
695
696
74
void EquipmentWindow::loadSlot(XmlNodeConstPtr slotNode,
697
                               const ImageSet *const imageset,
698
                               const int page)
699
{
700
74
    if (imageset == nullptr)
701
        return;
702

444
    const int slot = parseSlotName(XML::getProperty(slotNode, "name", ""));
703
74
    if (slot < 0)
704
        return;
705
706
    const int x = XML::getProperty(slotNode, "x", 0) + getPadding();
707
    const int y = XML::getProperty(slotNode, "y", 0)
708
        + getTitleBarHeight() + mYPadding;
709
    const int imageIndex = XML::getProperty(slotNode, "image", -1);
710
    Image *image = nullptr;
711
712
    if (imageIndex >= 0 && imageIndex < CAST_S32(imageset->size()))
713
        image = imageset->get(imageIndex);
714
715
    STD_VECTOR<EquipmentBox*> &boxes = mPages[page]->boxes;
716
    if (boxes[slot] != nullptr)
717
    {
718
        EquipmentBox *const box = boxes[slot];
719
        box->x = x;
720
        box->y = y;
721
        box->image = image;
722
    }
723
    else
724
    {
725
        boxes[slot] = new EquipmentBox(x, y, image);
726
    }
727
    if (x < mMinX)
728
        mMinX = x;
729
    if (y < mMinY)
730
        mMinY = y;
731
    if (x + mBoxSize > mMaxX)
732
        mMaxX = x + mBoxSize;
733
    if (y + mBoxSize > mMaxY)
734
        mMaxY = y + mBoxSize;
735
}
736
737
void EquipmentWindow::prepareSlotNames()
738
{
739
    mSlotNames.clear();
740
    XML::Document doc(paths.getStringValue("equipmentSlotsFile"),
741
        UseVirtFs_true,
742
        SkipError_false);
743
    XmlNodeConstPtrConst root = doc.rootNode();
744
    if (root == nullptr)
745
        return;
746
747
    for_each_xml_child_node(slotNode, root)
748
    {
749
        if (!xmlNameEqual(slotNode, "slot"))
750
            continue;
751
        const std::string name = XML::getProperty(slotNode, "name", "");
752
        if (name.empty())
753
        {
754
            reportAlways("Empty slot name detected.");
755
            continue;
756
        }
757
758
        const int slot = XML::getProperty(slotNode, "slot", -1);
759
        if (slot < 0 || slot >= BOX_COUNT)
760
        {
761
            reportAlways("Wrong slot id '%d' for slot with name '%s'",
762
                slot,
763
                name.c_str());
764
            continue;
765
        }
766
        mSlotNames[name] = slot;
767
    }
768
}
769
770
int EquipmentWindow::parseSlotName(const std::string &name)
771
{
772
148
    StringIntMapCIter it =  mSlotNames.find(name);
773

74
    if (it != mSlotNames.end())
774
        return (*it).second;
775
    return -1;
776
}
777
778
void EquipmentWindow::fillDefault()
779
{
780
    if (mImageSet != nullptr)
781
        mImageSet->decRef();
782
783
    addDefaultPage();
784
    mImageSet = Theme::getImageSetFromTheme(
785
        "equipmentbox.png", 32, 32);
786
787
    addBox(0, 90, 40, 0);     // torso
788
    addBox(1, 8, 78, 1);      // gloves
789
    addBox(2, 70, 0, 2);      // hat
790
    addBox(3, 50, 253, 3);    // pants
791
    addBox(4, 90, 253, 4);    // boots
792
    addBox(5, 8, 213, 5);     // FREE
793
    addBox(6, 129, 213, 6);   // wings
794
    addBox(7, 50, 40, 5);     // scarf
795
    addBox(8, 8, 168, 7);     // weapon
796
    addBox(9, 129, 168, 8);   // shield
797
    addBox(10, 129, 78, 9);   // ammo
798
    addBox(11, 8, 123, 5);    // amulet
799
    addBox(12, 129, 123, 5);  // ring
800
}
801
802
void EquipmentWindow::addBox(const int idx, int x, int y, const int imageIndex)
803
{
804
    Image *image = nullptr;
805
806
    if ((mImageSet != nullptr) && imageIndex >= 0 && imageIndex
807
        < CAST_S32(mImageSet->size()))
808
    {
809
        image = mImageSet->get(imageIndex);
810
    }
811
812
    x += getPadding();
813
    y += getTitleBarHeight() + mYPadding;
814
    STD_VECTOR<EquipmentBox*> &boxes = mPages[0]->boxes;
815
    boxes[idx] = new EquipmentBox(x, y, image);
816
817
    if (x < mMinX)
818
        mMinX = x;
819
    if (y < mMinY)
820
        mMinY = y;
821
    if (x + mBoxSize > mMaxX)
822
        mMaxX = x + mBoxSize;
823
    if (y + mBoxSize > mMaxY)
824
        mMaxY = y + mBoxSize;
825
}
826
827
2
void EquipmentWindow::recalcSize()
828
{
829
2
    mMaxX += mMinX;
830
2
    mMaxY += mMinY;
831
2
    mTabs->setWidth(mMaxX);
832
4
    mMaxY += mUnequip->getHeight() - mYPadding;
833
2
    setDefaultSize(mMaxX, mMaxY, ImagePosition::CENTER);
834
2
}
835
836
4
int EquipmentWindow::addPage(const std::string &name)
837
{
838
8
    EquipmentPage *const page = new EquipmentPage;
839
4
    mPages.push_back(page);
840
4
    STD_VECTOR<EquipmentBox*> &boxes = page->boxes;
841
842
4
    boxes.reserve(BOX_COUNT);
843
220
    for (int f = 0; f < BOX_COUNT; f ++)
844
216
        boxes.push_back(nullptr);
845
846
4
    mTabs->addButton(name, name, false);
847
8
    return CAST_S32(mPages.size()) - 1;
848

6
}