GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/ministatuswindow.cpp Lines: 110 273 40.3 %
Date: 2017-11-29 Branches: 122 394 31.0 %

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/ministatuswindow.h"
24
25
#include "configuration.h"
26
27
#include "being/localplayer.h"
28
#include "being/playerinfo.h"
29
30
#include "gui/popupmanager.h"
31
#include "gui/skin.h"
32
33
#include "gui/popups/popupmenu.h"
34
#include "gui/popups/statuspopup.h"
35
#include "gui/popups/textpopup.h"
36
37
#include "gui/windows/statuswindow.h"
38
39
#include "gui/widgets/createwidget.h"
40
#include "gui/widgets/progressbar.h"
41
42
#include "net/playerhandler.h"
43
44
#include "resources/inventory/inventory.h"
45
46
#include "resources/sprite/animatedsprite.h"
47
48
#include "utils/delete2.h"
49
#include "utils/dtor.h"
50
#include "utils/foreach.h"
51
#include "utils/gettext.h"
52
53
#include "debug.h"
54
55
MiniStatusWindow *miniStatusWindow = nullptr;
56
extern volatile int tick_time;
57
58
typedef STD_VECTOR <ProgressBar*>::const_iterator ProgressBarVectorCIter;
59
60
2
MiniStatusWindow::MiniStatusWindow() :
61
    Window("MiniStatus", Modal_false, nullptr, "ministatus.xml"),
62
    InventoryListener(),
63
    AttributeListener(),
64
    StatListener(),
65
    ArrowsListener(),
66
    UpdateStatusListener(),
67
    mBars(),
68
    mBarNames(),
69
    mIcons(),
70


26
    mHpBar(createBar(0, 100, 0, ThemeColorId::HP_BAR, ProgressColorId::PROG_HP,
71
        "hpprogressbar.xml", "hpprogressbar_fill.xml",
72
        // TRANSLATORS: status bar name
73
2
        "hp bar", _("health bar"))),
74





28
    mMpBar(createBar(0, 100, 0, playerHandler->canUseMagic()
75
        ? ThemeColorId::MP_BAR : ThemeColorId::NO_MP_BAR,
76
2
        playerHandler->canUseMagic()
77
        ? ProgressColorId::PROG_MP : ProgressColorId::PROG_NO_MP,
78
2
        playerHandler->canUseMagic()
79
        ? "mpprogressbar.xml" : "nompprogressbar.xml",
80
2
        playerHandler->canUseMagic()
81
        ? "mpprogressbar_fill.xml" : "nompprogressbar_fill.xml",
82
        // TRANSLATORS: status bar name
83
2
        "mp bar", _("mana bar"))),
84


26
    mXpBar(createBar(0, 100, 0,
85
        ThemeColorId::XP_BAR, ProgressColorId::PROG_EXP,
86
        "xpprogressbar.xml", "xpprogressbar_fill.xml",
87
        // TRANSLATORS: status bar name
88
2
        "xp bar", _("experience bar"))),
89
    mJobBar(nullptr),
90


26
    mWeightBar(createBar(0, 140, 0, ThemeColorId::WEIGHT_BAR,
91
        ProgressColorId::PROG_WEIGHT,
92
        "weightprogressbar.xml", "weightprogressbar_fill.xml",
93
        // TRANSLATORS: status bar name
94
2
        "weight bar", _("weight bar"))),
95


26
    mInvSlotsBar(createBar(0, 45, 0,
96
        ThemeColorId::SLOTS_BAR, ProgressColorId::PROG_INVY_SLOTS,
97
        "slotsprogressbar.xml", "slotsprogressbar_fill.xml",
98
        "inventory slots bar",
99
        // TRANSLATORS: status bar name
100
2
        _("inventory slots bar"))),
101


26
    mMoneyBar(createBar(0, 130, 0, ThemeColorId::MONEY_BAR,
102
        ProgressColorId::PROG_MONEY,
103
        "moneyprogressbar.xml", "moneyprogressbar_fill.xml",
104
        // TRANSLATORS: status bar name
105
2
        "money bar", _("money bar"))),
106


26
    mArrowsBar(createBar(0, 50, 0, ThemeColorId::ARROWS_BAR,
107
        ProgressColorId::PROG_ARROWS,
108
        "arrowsprogressbar.xml", "arrowsprogressbar_fill.xml",
109
        // TRANSLATORS: status bar name
110
2
        "arrows bar", _("arrows bar"))),
111




32
    mStatusBar(createBar(100, (config.getIntValue("fontSize") > 16
112
        ? 270 : 180), 0, ThemeColorId::STATUS_BAR,
113
        ProgressColorId::PROG_STATUS,
114
        "statusprogressbar.xml", "statusprogressbar_fill.xml",
115
        // TRANSLATORS: status bar name
116
2
        "status bar", _("status bar"))),
117

2
    mStatusPopup(CREATEWIDGETR0(StatusPopup)),
118


8
    mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 3) : 3),
119


8
    mIconPadding(mSkin != nullptr ? mSkin->getOption("iconPadding", 3) : 3),
120


8
    mIconSpacing(mSkin != nullptr ? mSkin->getOption("iconSpacing", 2) : 2),
121



50
    mMaxX(0)
122
{
123
2
    StatusWindow::updateHPBar(mHpBar);
124
125
2
    if (statusWindow != nullptr)
126
        statusWindow->updateMPBar(mMpBar);
127
128

8
    const bool job = serverConfig.getValueBool("showJob", true);
129
130
2
    StatusWindow::updateXPBar(mXpBar);
131
132
2
    if (job)
133
    {
134


26
        mJobBar = createBar(0, 100, 0,
135
            ThemeColorId::JOB_BAR,
136
            ProgressColorId::PROG_JOB,
137
            "jobprogressbar.xml", "jobprogressbar_fill.xml",
138
            // TRANSLATORS: status bar name
139
2
            "job bar", _("job bar"));
140
2
        StatusWindow::updateJobBar(mJobBar);
141
    }
142
143
2
    loadBars();
144
2
    updateBars();
145
146
2
    setVisible(Visible_true);
147
2
    addMouseListener(this);
148
2
    Inventory *const inv = PlayerInfo::getInventory();
149
2
    if (inv != nullptr)
150
        inv->addInventoyListener(this);
151
152
2
    StatusWindow::updateMoneyBar(mMoneyBar);
153
2
    StatusWindow::updateArrowsBar(mArrowsBar);
154
2
    updateStatus();
155
2
}
156
157
14
MiniStatusWindow::~MiniStatusWindow()
158
{
159
2
    delete2(mStatusPopup);
160
4
    delete_all(mIcons);
161
4
    mIcons.clear();
162
163
2
    Inventory *const inv = PlayerInfo::getInventory();
164
2
    if (inv != nullptr)
165
        inv->removeInventoyListener(this);
166
167
30
    FOR_EACH (ProgressBarVectorCIter, it, mBars)
168
    {
169
18
        ProgressBar *bar = *it;
170
18
        if (bar == nullptr)
171
            continue;
172
18
        if (bar->mVisible == Visible_false)
173
10
            delete bar;
174
    }
175
4
    mBars.clear();
176
4
}
177
178
18
ProgressBar *MiniStatusWindow::createBar(const float progress,
179
                                         const int width,
180
                                         const int height,
181
                                         const ThemeColorIdT textColor,
182
                                         const ProgressColorIdT backColor,
183
                                         const std::string &restrict skin,
184
                                         const std::string &restrict skinFill,
185
                                         const std::string &restrict name,
186
                                         const std::string &restrict
187
                                         description)
188
{
189
    ProgressBar *const bar = new ProgressBar(this,
190
18
        progress, width, height, backColor, skin, skinFill);
191
36
    bar->setActionEventId(name);
192
36
    bar->setId(description);
193
54
    bar->setColor(getThemeColor(textColor), getThemeColor(textColor + 1));
194
18
    mBars.push_back(bar);
195
18
    mBarNames[name] = bar;
196
18
    return bar;
197
}
198
199
2
void MiniStatusWindow::updateBars()
200
{
201
2
    int x = 0;
202
2
    const ProgressBar *lastBar = nullptr;
203
30
    FOR_EACH (ProgressBarVectorCIter, it, mBars)
204
18
        remove(*it);
205
206
30
    FOR_EACH (ProgressBarVectorCIter, it, mBars)
207
    {
208
18
        ProgressBar *const bar = *it;
209
18
        if (bar == nullptr)
210
            continue;
211
18
        if (bar->mVisible == Visible_true)
212
        {
213
8
            bar->setPosition(x, 0);
214
8
            add(bar);
215
16
            x += bar->getWidth() + mSpacing;
216
8
            lastBar = bar;
217
        }
218
    }
219
220
2
    if (lastBar != nullptr)
221
    {
222
8
        setContentSize(lastBar->getX() + lastBar->getWidth(),
223
6
            lastBar->getY() + lastBar->getHeight());
224
    }
225
2
    mMaxX = x;
226
2
}
227
228
void MiniStatusWindow::setIcon(const int index, AnimatedSprite *const sprite)
229
{
230
    if (index >= CAST_S32(mIcons.size()))
231
        mIcons.resize(index + 1, nullptr);
232
233
    delete mIcons[index];
234
    mIcons[index] = sprite;
235
}
236
237
void MiniStatusWindow::eraseIcon(const int index)
238
{
239
    if (index < CAST_S32(mIcons.size()))
240
    {
241
        delete mIcons[index];
242
        mIcons.erase(mIcons.begin() + index);
243
    }
244
}
245
246
void MiniStatusWindow::drawIcons(Graphics *const graphics)
247
{
248
    // Draw icons
249
    int icon_x = mMaxX + mIconPadding;
250
    for (size_t i = 0, sz = mIcons.size(); i < sz; i ++)
251
    {
252
        const AnimatedSprite *const icon = mIcons[i];
253
        if (icon != nullptr)
254
        {
255
            icon->draw(graphics, icon_x, mIconPadding);
256
            icon_x += mIconSpacing + icon->getWidth();
257
        }
258
    }
259
}
260
261
void MiniStatusWindow::statChanged(const AttributesT id A_UNUSED,
262
                                   const int oldVal1 A_UNUSED,
263
                                   const int oldVal2 A_UNUSED)
264
{
265
    if (statusWindow != nullptr)
266
        statusWindow->updateMPBar(mMpBar);
267
    StatusWindow::updateJobBar(mJobBar);
268
}
269
270
void MiniStatusWindow::attributeChanged(const AttributesT id,
271
                                        const int64_t oldVal A_UNUSED,
272
                                        const int64_t newVal A_UNUSED)
273
{
274
    PRAGMA45(GCC diagnostic push)
275
    PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
276
    switch (id)
277
    {
278
        case Attributes::PLAYER_HP:
279
        case Attributes::PLAYER_MAX_HP:
280
            StatusWindow::updateHPBar(mHpBar);
281
            break;
282
        case Attributes::PLAYER_MP:
283
        case Attributes::PLAYER_MAX_MP:
284
            statusWindow->updateMPBar(mMpBar);
285
            break;
286
        case Attributes::PLAYER_EXP:
287
        case Attributes::PLAYER_EXP_NEEDED:
288
            StatusWindow::updateXPBar(mXpBar);
289
            break;
290
        case Attributes::TOTAL_WEIGHT:
291
        case Attributes::MAX_WEIGHT:
292
            StatusWindow::updateWeightBar(mWeightBar);
293
            break;
294
        case Attributes::MONEY:
295
            StatusWindow::updateMoneyBar(mMoneyBar);
296
            break;
297
        default:
298
            break;
299
    }
300
    PRAGMA45(GCC diagnostic pop)
301
}
302
303
2
void MiniStatusWindow::updateStatus()
304
{
305
2
    if (statusWindow != nullptr)
306
        statusWindow->updateStatusBar(mStatusBar);
307

2
    if ((mStatusPopup != nullptr) && mStatusPopup->isPopupVisible())
308
        mStatusPopup->update();
309
2
}
310
311
void MiniStatusWindow::logic()
312
{
313
    BLOCK_START("MiniStatusWindow::logic")
314
    Window::logic();
315
316
    for (size_t i = 0, sz = mIcons.size(); i < sz; i++)
317
    {
318
        AnimatedSprite *const icon = mIcons[i];
319
        if (icon != nullptr)
320
            icon->update(tick_time * 10);
321
    }
322
    BLOCK_END("MiniStatusWindow::logic")
323
}
324
325
2
void MiniStatusWindow::draw(Graphics *const graphics)
326
{
327
    BLOCK_START("MiniStatusWindow::draw")
328
2
    drawChildren(graphics);
329
    BLOCK_END("MiniStatusWindow::draw")
330
2
}
331
332
void MiniStatusWindow::safeDraw(Graphics *const graphics)
333
{
334
    BLOCK_START("MiniStatusWindow::draw")
335
    safeDrawChildren(graphics);
336
    BLOCK_END("MiniStatusWindow::draw")
337
}
338
339
void MiniStatusWindow::mouseMoved(MouseEvent &event)
340
{
341
    Window::mouseMoved(event);
342
343
    const int x = event.getX();
344
    const int y = event.getY();
345
346
    const Rect &rect = mDimension;
347
    if (event.getSource() == mStatusBar)
348
    {
349
        mStatusPopup->view(x + rect.x, y + rect.y);
350
        textPopup->hide();
351
    }
352
    else if (event.getSource() == mXpBar)
353
    {
354
        std::string level;
355
        if ((localPlayer != nullptr) && localPlayer->isGM())
356
        {
357
            // TRANSLATORS: status bar label
358
            level = strprintf(_("Level: %d (GM %d)"),
359
                PlayerInfo::getAttribute(Attributes::PLAYER_BASE_LEVEL),
360
                localPlayer->getGroupId());
361
        }
362
        else
363
        {
364
            // TRANSLATORS: status bar label
365
            level = strprintf(_("Level: %d"),
366
                PlayerInfo::getAttribute(Attributes::PLAYER_BASE_LEVEL));
367
        }
368
369
        const int64_t exp = PlayerInfo::getAttribute64(Attributes::PLAYER_EXP);
370
        const int64_t expNeed = PlayerInfo::getAttribute64(
371
            Attributes::PLAYER_EXP_NEEDED);
372
        const std::string str = toString(CAST_U64(exp)) +
373
            "/" +
374
            toString(CAST_U64(expNeed));
375
        if (exp > expNeed)
376
        {
377
            textPopup->show(x + rect.x,
378
                y + rect.y,
379
                level,
380
                str);
381
        }
382
        else
383
        {
384
            const std::string str2 = toString(CAST_U64(expNeed - exp));
385
            textPopup->show(x + rect.x,
386
                y + rect.y,
387
                level,
388
                str,
389
                // TRANSLATORS: status bar label
390
                strprintf("%s: %s", _("Need"), str2.c_str()));
391
        }
392
        mStatusPopup->hide();
393
    }
394
    else if (event.getSource() == mHpBar)
395
    {
396
        textPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(),
397
            strprintf("%d/%d", PlayerInfo::getAttribute(Attributes::PLAYER_HP),
398
            PlayerInfo::getAttribute(Attributes::PLAYER_MAX_HP)));
399
        mStatusPopup->hide();
400
    }
401
    else if (event.getSource() == mMpBar)
402
    {
403
        textPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(),
404
            strprintf("%d/%d", PlayerInfo::getAttribute(Attributes::PLAYER_MP),
405
            PlayerInfo::getAttribute(Attributes::PLAYER_MAX_MP)));
406
        mStatusPopup->hide();
407
    }
408
    else if (event.getSource() == mJobBar)
409
    {
410
        const int64_t exp =  PlayerInfo::getAttribute64(
411
            Attributes::PLAYER_JOB_EXP);
412
        const int64_t expNeed =  PlayerInfo::getAttribute64(
413
            Attributes::PLAYER_JOB_EXP_NEEDED);
414
        const int32_t jobLevel = PlayerInfo::getAttribute(
415
            Attributes::PLAYER_JOB_LEVEL);
416
        const std::string expStr = toString(CAST_U64(exp));
417
        const std::string expNeedStr = toString(CAST_U64(expNeed));
418
        const std::string expLeftStr = toString(CAST_U64(expNeed - exp));
419
420
        // TRANSLATORS: job bar label
421
        const std::string level = strprintf(_("Job level: %d"),
422
            jobLevel);
423
424
        if (exp > expNeed)
425
        {
426
            textPopup->show(x + rect.x,
427
                y + rect.y,
428
                level,
429
                strprintf("%s/%s", expStr.c_str(), expNeedStr.c_str()));
430
        }
431
        else
432
        {
433
            textPopup->show(x + rect.x,
434
                y + rect.y,
435
                level,
436
                strprintf("%s/%s", expStr.c_str(), expNeedStr.c_str()),
437
                // TRANSLATORS: status bar label
438
                strprintf("%s: %s", _("Need"), expLeftStr.c_str()));
439
        }
440
        mStatusPopup->hide();
441
    }
442
    else if (event.getSource() == mWeightBar)
443
    {
444
        textPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(),
445
            strprintf("%d/%d", PlayerInfo::getAttribute(
446
            Attributes::TOTAL_WEIGHT),
447
            PlayerInfo::getAttribute(Attributes::MAX_WEIGHT)));
448
        mStatusPopup->hide();
449
    }
450
    else if (event.getSource() == mInvSlotsBar)
451
    {
452
        const Inventory *const inv = PlayerInfo::getInventory();
453
        if (inv != nullptr)
454
        {
455
            const int usedSlots = inv->getNumberOfSlotsUsed();
456
            const int maxSlots = inv->getSize();
457
            textPopup->show(x + rect.x, y + rect.y,
458
                event.getSource()->getId(),
459
                strprintf("%d/%d", usedSlots, maxSlots));
460
        }
461
        mStatusPopup->hide();
462
    }
463
    else if (event.getSource() == mMoneyBar)
464
    {
465
        textPopup->show(x + rect.x, y + rect.y,
466
            event.getSource()->getId(),
467
            toString(PlayerInfo::getAttribute(Attributes::MONEY)));
468
    }
469
    else
470
    {
471
        textPopup->hide();
472
        mStatusPopup->hide();
473
    }
474
}
475
476
void MiniStatusWindow::mousePressed(MouseEvent &event)
477
{
478
    if (event.getButton() == MouseButton::RIGHT)
479
    {
480
        const ProgressBar *const bar = dynamic_cast<ProgressBar*>(
481
            event.getSource());
482
        if (bar == nullptr)
483
            return;
484
        event.consume();
485
        if (popupManager != nullptr)
486
        {
487
            popupMenu->showPopup(getX() + event.getX(),
488
                getY() + event.getY(), bar);
489
        }
490
    }
491
}
492
493
void MiniStatusWindow::mouseExited(MouseEvent &event)
494
{
495
    Window::mouseExited(event);
496
497
    textPopup->hide();
498
    mStatusPopup->hide();
499
}
500
501
void MiniStatusWindow::showBar(const std::string &name,
502
                               const Visible visible)
503
{
504
    ProgressBar *const bar = mBarNames[name];
505
    if (bar == nullptr)
506
        return;
507
    bar->setVisible(visible);
508
    updateBars();
509
    saveBars();
510
}
511
512
2
void MiniStatusWindow::loadBars()
513
{
514

8
    if (config.getIntValue("ministatussaved") == 0)
515
    {
516
2
        if (mWeightBar != nullptr)
517
2
            mWeightBar->setVisible(Visible_false);
518
2
        if (mInvSlotsBar != nullptr)
519
2
            mInvSlotsBar->setVisible(Visible_false);
520
2
        if (mMoneyBar != nullptr)
521
2
            mMoneyBar->setVisible(Visible_false);
522
2
        if (mArrowsBar != nullptr)
523
2
            mArrowsBar->setVisible(Visible_false);
524
2
        if (mStatusBar != nullptr)
525
2
            mStatusBar->setVisible(Visible_false);
526
2
        if (mJobBar != nullptr)
527
2
            mJobBar->setVisible(Visible_true);
528
        return;
529
    }
530
531
    for (int f = 0; f < 10; f ++)
532
    {
533
        const std::string str = config.getValue(
534
            "ministatus" + toString(f), "");
535
        if (str.empty())
536
            continue;
537
        ProgressBar *const bar = mBarNames[str];
538
        if (bar == nullptr)
539
            continue;
540
        bar->setVisible(Visible_false);
541
    }
542
}
543
544
void MiniStatusWindow::saveBars() const
545
{
546
    int i = 0;
547
    FOR_EACH (ProgressBarVectorCIter, it, mBars)
548
    {
549
        const ProgressBar *const bar = *it;
550
        if (bar->mVisible == Visible_false)
551
        {
552
            config.setValue("ministatus" + toString(i),
553
                bar->getActionEventId());
554
            i ++;
555
        }
556
    }
557
    for (int f = i; f < 10; f ++)
558
        config.deleteKey("ministatus" + toString(f));
559
560
    config.setValue("ministatussaved", true);
561
}
562
563
void MiniStatusWindow::slotsChanged(const Inventory *const inventory)
564
{
565
    if (inventory == nullptr)
566
        return;
567
568
    if (inventory->getType() == InventoryType::Inventory)
569
        StatusWindow::updateInvSlotsBar(mInvSlotsBar);
570
}
571
572
2
Rect MiniStatusWindow::getChildrenArea()
573
{
574
2
    const int padding = mPadding;
575
2
    const int padding2 = padding * 2;
576
2
    const Rect &rect = mDimension;
577
    return Rect(padding, padding,
578
2
        rect.width - padding2,
579
6
        rect.height - padding2);
580
}
581
582
void MiniStatusWindow::arrowsChanged()
583
{
584
    StatusWindow::updateArrowsBar(mArrowsBar);
585
4
}
586
587
#ifdef USE_PROFILER
588
void MiniStatusWindow::logicChildren()
589
{
590
    BLOCK_START("MiniStatusWindow::logicChildren")
591
    BasicContainer::logicChildren();
592
    BLOCK_END("MiniStatusWindow::logicChildren")
593
}
594
#endif  // USE_PROFILER