GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/ministatuswindow.cpp Lines: 110 273 40.3 %
Date: 2018-05-24 20:11:55 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-2018  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
        false);
125
126
2
    if (statusWindow != nullptr)
127
    {
128
        statusWindow->updateMPBar(mMpBar,
129
            false);
130
    }
131
132

8
    const bool job = serverConfig.getValueBool("showJob", true);
133
134
2
    StatusWindow::updateXPBar(mXpBar,
135
        true);
136
137
2
    if (job)
138
    {
139


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

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

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