GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/popups/itempopup.cpp Lines: 50 234 21.4 %
Date: 2018-09-20 Branches: 37 298 12.4 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2008  The Legend of Mazzeroth Development Team
4
 *  Copyright (C) 2008-2009  The Mana World Development Team
5
 *  Copyright (C) 2009-2010  The Mana Developers
6
 *  Copyright (C) 2011-2018  The ManaPlus Developers
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/popups/itempopup.h"
25
26
#include "actormanager.h"
27
#include "configuration.h"
28
29
#include "gui/gui.h"
30
31
#include "gui/fonts/font.h"
32
33
#include "gui/widgets/icon.h"
34
#include "gui/widgets/label.h"
35
#include "gui/widgets/textbox.h"
36
37
#include "net/beinghandler.h"
38
#ifdef TMWA_SUPPORT
39
#include "net/net.h"
40
#endif  // TMWA_SUPPORT
41
42
#include "utils/foreach.h"
43
#include "utils/gettext.h"
44
#include "utils/stdmove.h"
45
46
#include "utils/translation/podict.h"
47
48
#include "resources/iteminfo.h"
49
50
#include "resources/db/itemoptiondb.h"
51
#include "resources/db/unitsdb.h"
52
53
#include "resources/image/image.h"
54
55
#include "resources/item/item.h"
56
#include "resources/item/itemfieldtype.h"
57
#include "resources/item/itemoptionslist.h"
58
59
#include "resources/loaders/imageloader.h"
60
61
#include "debug.h"
62
63
ItemPopup *itemPopup = nullptr;
64
65
2
ItemPopup::ItemPopup() :
66
    Popup("ItemPopup", "itempopup.xml"),
67

2
    mItemName(new Label(this)),
68

2
    mItemDesc(new TextBox(this)),
69

2
    mItemEffect(new TextBox(this)),
70

2
    mItemWeight(new TextBox(this)),
71

2
    mItemCards(new TextBox(this)),
72

2
    mItemOptions(new TextBox(this)),
73
    mItemType(ItemDbType::UNUSABLE),
74

2
    mIcon(new Icon(this, nullptr, AutoRelease_false)),
75
    mLastName(),
76
    mCardsStr(),
77
    mItemOptionsStr(),
78
    mLastId(0),
79

34
    mLastColor(ItemColor_one)
80
{
81
    // Item name
82
2
    mItemName->setFont(boldFont);
83
2
    mItemName->setPosition(0, 0);
84
85

2
    const int fontHeight = getFont()->getHeight();
86
87
    // Item description
88
2
    mItemDesc->setEditable(false);
89
2
    mItemDesc->setPosition(0, fontHeight);
90
6
    mItemDesc->setForegroundColorAll(
91
        getThemeColor(ThemeColorId::POPUP, 255U),
92
2
        getThemeColor(ThemeColorId::POPUP_OUTLINE, 255U));
93
94
    // Item effect
95
2
    mItemEffect->setEditable(false);
96
2
    mItemEffect->setPosition(0, 2 * fontHeight);
97
6
    mItemEffect->setForegroundColorAll(
98
        getThemeColor(ThemeColorId::POPUP, 255U),
99
2
        getThemeColor(ThemeColorId::POPUP_OUTLINE, 255U));
100
101
    // Item weight
102
2
    mItemWeight->setEditable(false);
103
2
    mItemWeight->setPosition(0, 3 * fontHeight);
104
6
    mItemWeight->setForegroundColorAll(
105
        getThemeColor(ThemeColorId::POPUP, 255U),
106
2
        getThemeColor(ThemeColorId::POPUP_OUTLINE, 255U));
107
108
    // Item cards
109
2
    mItemCards->setEditable(false);
110
2
    mItemCards->setPosition(0, 4 * fontHeight);
111
6
    mItemCards->setForegroundColorAll(
112
        getThemeColor(ThemeColorId::POPUP, 255U),
113
2
        getThemeColor(ThemeColorId::POPUP_OUTLINE, 255U));
114
115
    // Item options
116
2
    mItemOptions->setEditable(false);
117
2
    mItemOptions->setPosition(0, 5 * fontHeight);
118
6
    mItemOptions->setForegroundColorAll(
119
        getThemeColor(ThemeColorId::POPUP, 255U),
120
2
        getThemeColor(ThemeColorId::POPUP_OUTLINE, 255U));
121
2
}
122
123
2
void ItemPopup::postInit()
124
{
125
4
    Popup::postInit();
126
2
    add(mItemName);
127
2
    add(mItemDesc);
128
2
    add(mItemEffect);
129
2
    add(mItemWeight);
130
2
    add(mItemCards);
131
2
    add(mItemOptions);
132
2
    add(mIcon);
133
134
2
    addMouseListener(this);
135
2
}
136
137
12
ItemPopup::~ItemPopup()
138
{
139
2
    if (mIcon != nullptr)
140
    {
141
4
        Image *const image = mIcon->getImage();
142
2
        if (image != nullptr)
143
            image->decRef();
144
    }
145
4
}
146
147
void ItemPopup::setItem(const Item *const item,
148
                        const bool showImage)
149
{
150
    if (item == nullptr)
151
        return;
152
153
    const ItemInfo &ii = item->getInfo();
154
    setItem(ii,
155
        item->getColor(),
156
        showImage,
157
        item->getId(),
158
        item->getCards(),
159
        item->getOptions());
160
    if (item->getRefine() > 0)
161
    {
162
        mLastName = ii.getName();
163
        mLastColor = item->getColor();
164
        mLastId = item->getId();
165
#ifdef TMWA_SUPPORT
166
        if (Net::getNetworkType() == ServerType::TMWATHENA)
167
        {
168
            mItemName->setCaption(strprintf("%s (+%u), %d",
169
                ii.getName().c_str(),
170
                CAST_U32(item->getRefine()),
171
                ii.getId()));
172
        }
173
        else
174
#endif  // TMWA_SUPPORT
175
        {
176
            mItemName->setCaption(strprintf("%s (+%u), %d",
177
                ii.getName(item->getColor()).c_str(),
178
                CAST_U32(item->getRefine()),
179
                ii.getId()));
180
        }
181
        mItemName->adjustSize();
182
        const unsigned minWidth = mItemName->getWidth() + 8;
183
        if (CAST_U32(getWidth()) < minWidth)
184
            setWidth(minWidth);
185
    }
186
}
187
188
void ItemPopup::setItem(const ItemInfo &item,
189
                        const ItemColor color,
190
                        const bool showImage,
191
                        int id,
192
                        const int *const cards,
193
                        const ItemOptionsList *const options)
194
{
195
    if (mIcon == nullptr)
196
        return;
197
198
    std::string cardsStr;
199
    std::string optionsStr;
200
201
    if (item.getName() == mLastName &&
202
        color == mLastColor &&
203
        id == mLastId)
204
    {
205
        cardsStr = getCardsString(cards);
206
        optionsStr = getOptionsString(options);
207
        if (mItemOptionsStr == optionsStr &&
208
            mCardsStr == cardsStr)
209
        {
210
            return;
211
        }
212
    }
213
    else
214
    {
215
        cardsStr = getCardsString(cards);
216
        optionsStr = getOptionsString(options);
217
    }
218
    mItemOptionsStr = STD_MOVE(optionsStr);
219
    mCardsStr = STD_MOVE(cardsStr);
220
221
    if (id == -1)
222
        id = item.getId();
223
224
    int space = 0;
225
226
    Image *const oldImage = mIcon->getImage();
227
    if (oldImage != nullptr)
228
        oldImage->decRef();
229
230
    if (showImage)
231
    {
232
        Image *const image = Loader::getImage(combineDye2(
233
            pathJoin(paths.getStringValue("itemIcons"),
234
            item.getDisplay().image),
235
            item.getDyeIconColorsString(color)));
236
237
        mIcon->setImage(image);
238
        if (image != nullptr)
239
        {
240
            mIcon->setPosition(0, 0);
241
            space = mIcon->getWidth();
242
        }
243
    }
244
    else
245
    {
246
        mIcon->setImage(nullptr);
247
    }
248
249
    mItemType = item.getType();
250
251
    mLastName = item.getName();
252
    mLastColor = color;
253
    mLastId = id;
254
255
#ifdef TMWA_SUPPORT
256
    if (Net::getNetworkType() == ServerType::TMWATHENA)
257
    {
258
        mItemName->setCaption(strprintf("%s, %d",
259
            item.getName().c_str(), id));
260
        mItemDesc->setTextWrapped(item.getDescription(), 196);
261
    }
262
    else
263
#endif  // TMWA_SUPPORT
264
    {
265
        mItemName->setCaption(strprintf("%s, %d",
266
            item.getName(color).c_str(), id));
267
        mItemDesc->setTextWrapped(item.getDescription(color), 196);
268
    }
269
270
    mItemName->adjustSize();
271
    setLabelColor(mItemName, mItemType);
272
    mItemName->setPosition(space, 0);
273
274
    mItemEffect->setTextWrapped(item.getEffect(), 196);
275
    // TRANSLATORS: popup label
276
    mItemWeight->setTextWrapped(strprintf(_("Weight: %s"),
277
        UnitsDb::formatWeight(item.getWeight()).c_str()), 196);
278
    mItemCards->setTextWrapped(mCardsStr, 196);
279
    mItemOptions->setTextWrapped(mItemOptionsStr, 196);
280
281
    int minWidth = mItemName->getWidth() + space;
282
283
    if (mItemName->getWidth() + space > minWidth)
284
        minWidth = mItemName->getWidth() + space;
285
    if (mItemDesc->getMinWidth() > minWidth)
286
        minWidth = mItemDesc->getMinWidth();
287
    if (mItemEffect->getMinWidth() > minWidth)
288
        minWidth = mItemEffect->getMinWidth();
289
    if (mItemWeight->getMinWidth() > minWidth)
290
        minWidth = mItemWeight->getMinWidth();
291
    if (mItemCards->getMinWidth() > minWidth)
292
        minWidth = mItemCards->getMinWidth();
293
    if (mItemOptions->getMinWidth() > minWidth)
294
        minWidth = mItemOptions->getMinWidth();
295
296
    const int numRowsDesc = mItemDesc->getNumberOfRows();
297
    const int numRowsEffect = mItemEffect->getNumberOfRows();
298
    const int numRowsWeight = mItemWeight->getNumberOfRows();
299
    const int numRowsCards = mItemCards->getNumberOfRows();
300
    const int numRowsOptions = mItemOptions->getNumberOfRows();
301
    const int height = getFont()->getHeight();
302
303
    if (item.getEffect().empty())
304
    {
305
        setContentSize(minWidth,
306
            (numRowsDesc + 2 + numRowsWeight + numRowsCards + numRowsOptions) *
307
            height);
308
        mItemWeight->setPosition(0, (numRowsDesc + 2) * height);
309
        mItemCards->setPosition(0, (numRowsDesc + numRowsWeight + 2) * height);
310
        mItemOptions->setPosition(0,
311
            (numRowsDesc + numRowsWeight + numRowsCards + 2) * height);
312
    }
313
    else
314
    {
315
        setContentSize(minWidth, (numRowsDesc + numRowsEffect + 2
316
            + numRowsWeight + numRowsCards + numRowsOptions) * height);
317
        mItemEffect->setPosition(0, (numRowsDesc + 2) * height);
318
        mItemWeight->setPosition(0, (numRowsDesc + numRowsEffect + 2)
319
            * height);
320
        mItemCards->setPosition(0, (numRowsDesc + numRowsEffect
321
            + numRowsWeight + 2) * height);
322
        mItemOptions->setPosition(0, (numRowsDesc + numRowsEffect
323
            + numRowsWeight + numRowsCards + 2) * height);
324
    }
325
326
    mItemDesc->setPosition(0, 2 * height);
327
}
328
329
std::string ItemPopup::getCardsString(const int *const cards)
330
{
331
    if (cards == nullptr)
332
        return std::string();
333
334
    std::string label;
335
336
    switch (cards[0])
337
    {
338
        case 0xfe:  // named item
339
        {
340
            const int32_t charId = cards[2] + 65536 * cards[3];
341
            std::string name = actorManager->findCharById(charId);
342
            if (name.empty())
343
            {
344
                name = toString(charId);
345
                beingHandler->requestNameByCharId(charId);
346
                mLastId = 0;  // allow recreate popup with same data
347
            }
348
            // TRANSLATORS: named item description
349
            label.append(strprintf(_("Item named: %s"), name.c_str()));
350
            return label;
351
        }
352
        case 0x00FFU:  // forged item
353
        {
354
            return label;
355
        }
356
        case 0xFF00U:
357
        {
358
            return label;
359
        }
360
        default:
361
        {
362
            for (int f = 0; f < maxCards; f ++)
363
            {
364
                const int id = cards[f];
365
                if (id != 0)
366
                {
367
                    if (!label.empty())
368
                        label.append(" / ");
369
                    const ItemInfo &info = ItemDB::get(id);
370
                    label.append(info.getName());
371
                }
372
            }
373
            if (label.empty())
374
                return label;
375
            // TRANSLATORS: popup label
376
            return _("Cards: ") + label;
377
        }
378
    }
379
}
380
381
std::string ItemPopup::getOptionsString(const ItemOptionsList *const options)
382
{
383
    if (options == nullptr || translator == nullptr)
384
        return std::string();
385
    const size_t sz = options->size();
386
    std::string effect;
387
    for (size_t f = 0; f < sz; f ++)
388
    {
389
        const ItemOption &option = options->get(f);
390
        if (option.index == 0)
391
            continue;
392
        const STD_VECTOR<ItemFieldType*> &fields = ItemOptionDb::getFields(
393
            option.index);
394
        if (fields.empty())
395
            continue;
396
        const std::string valueStr = toString(option.value);
397
        FOR_EACH (STD_VECTOR<ItemFieldType*>::const_iterator, it, fields)
398
        {
399
            const ItemFieldType *const field = *it;
400
            std::string value = valueStr;
401
            if (!effect.empty())
402
                effect.append(" / ");
403
            if (field->sign && value[0] != '-')
404
                value = std::string("+").append(value);
405
            const std::string format = translator->getStr(field->description);
406
            effect.append(strprintf(format.c_str(),
407
                value.c_str()));
408
        }
409
    }
410
    if (effect.empty())
411
        return effect;
412
    // TRANSLATORS: popup label
413
    return _("Options: ") + effect;
414
}
415
416
#define caseSetColor(name1, name2) \
417
    case name1: \
418
    { \
419
        return label->setForegroundColorAll( \
420
        getThemeColor(name2, 255U), \
421
        getThemeColor(name2##_OUTLINE, 255U)); \
422
    }
423
void ItemPopup::setLabelColor(Label *label,
424
                              const ItemDbTypeT type) const
425
{
426
    switch (type)
427
    {
428
        caseSetColor(ItemDbType::UNUSABLE, ThemeColorId::GENERIC)
429
        caseSetColor(ItemDbType::USABLE, ThemeColorId::USABLE)
430
        caseSetColor(ItemDbType::EQUIPMENT_ONE_HAND_WEAPON,
431
            ThemeColorId::ONEHAND)
432
        caseSetColor(ItemDbType::EQUIPMENT_TWO_HANDS_WEAPON,
433
            ThemeColorId::TWOHAND)
434
        caseSetColor(ItemDbType::EQUIPMENT_TORSO, ThemeColorId::TORSO)
435
        caseSetColor(ItemDbType::EQUIPMENT_ARMS, ThemeColorId::ARMS)
436
        caseSetColor(ItemDbType::EQUIPMENT_HEAD, ThemeColorId::HEAD)
437
        caseSetColor(ItemDbType::EQUIPMENT_LEGS, ThemeColorId::LEGS)
438
        caseSetColor(ItemDbType::EQUIPMENT_SHIELD, ThemeColorId::SHIELD)
439
        caseSetColor(ItemDbType::EQUIPMENT_RING, ThemeColorId::RING)
440
        caseSetColor(ItemDbType::EQUIPMENT_NECKLACE, ThemeColorId::NECKLACE)
441
        caseSetColor(ItemDbType::EQUIPMENT_FEET, ThemeColorId::FEET)
442
        caseSetColor(ItemDbType::EQUIPMENT_AMMO, ThemeColorId::AMMO)
443
        caseSetColor(ItemDbType::EQUIPMENT_CHARM, ThemeColorId::CHARM)
444
        caseSetColor(ItemDbType::SPRITE_RACE, ThemeColorId::UNKNOWN_ITEM)
445
        caseSetColor(ItemDbType::SPRITE_HAIR, ThemeColorId::UNKNOWN_ITEM)
446
        caseSetColor(ItemDbType::CARD, ThemeColorId::CARD)
447
        default:
448
        {
449
            return label->setForegroundColorAll(
450
                getThemeColor(ThemeColorId::UNKNOWN_ITEM, 255U),
451
                getThemeColor(ThemeColorId::UNKNOWN_ITEM_OUTLINE, 255U));
452
        }
453
    }
454
}
455
#undef caseSetColor
456
457
void ItemPopup::mouseMoved(MouseEvent &event)
458
{
459
    Popup::mouseMoved(event);
460
461
    // When the mouse moved on top of the popup, hide it
462
    setVisible(Visible_false);
463
    resetPopup();
464
}
465
466
void ItemPopup::resetPopup()
467
{
468
    mLastName.clear();
469
    mLastColor = ItemColor_one;
470
    mLastId = 0;
471
2
}