GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windowmenu.cpp Lines: 1 272 0.4 %
Date: 2021-03-17 Branches: 2 360 0.6 %

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/windowmenu.h"
25
26
#include "configuration.h"
27
#include "settings.h"
28
29
#include "input/inputmanager.h"
30
31
#include "gui/buttoninfo.h"
32
#include "gui/buttontext.h"
33
#include "gui/popupmanager.h"
34
#include "gui/skin.h"
35
36
#include "gui/popups/popupmenu.h"
37
#include "gui/popups/textpopup.h"
38
39
#include "gui/windows/skilldialog.h"
40
41
#include "gui/widgets/button.h"
42
43
#include "utils/dtor.h"
44
#include "utils/foreach.h"
45
#include "utils/gettext.h"
46
47
#include "resources/imageset.h"
48
49
#include "debug.h"
50
51
WindowMenu *windowMenu = nullptr;
52
53
WindowMenu::WindowMenu(const Widget2 *const widget) :
54
    Container(widget),
55
    ConfigListener(),
56
    ActionListener(),
57
    SelectionListener(),
58
    MouseListener(),
59
    mSkin(theme != nullptr ? theme->load("windowmenu.xml", "",
60
        true, Theme::getThemePath()) : nullptr),
61
    mImageSet(nullptr),
62
    mPadding(mSkin != nullptr ? mSkin->getPadding() : 1),
63
    mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 3) : 3),
64
    mButtons(),
65
    mButtonTexts(),
66
    mButtonNames(),
67
    mHaveMouse(false),
68
    mAutoHide(1),
69
    mSmallWindow(mainGraphics->getWidth() < 600)
70
{
71
    int x = mPadding;
72
    int h = 0;
73
74
    setFocusable(false);
75
76
    if (settings.showButtonIcons)
77
    {
78
        mImageSet = Theme::getImageSetFromTheme("buttonsicons.png",
79
            mSkin->getOption("imageWidth", 20),
80
            mSkin->getOption("imageHeight", 20));
81
    }
82
83
    // TRANSLATORS: short button name for who is online window.
84
    addButton(N_("ONL"),
85
        13,
86
        // TRANSLATORS: long button name for who is online window.
87
        _("Who is online"), x, h, InputAction::WINDOW_ONLINE,
88
        Visible_true);
89
    // TRANSLATORS: short button name for help window.
90
    addButton(N_("HLP"),
91
        0,
92
        // TRANSLATORS: long button name for help window.
93
        _("Help"), x, h, InputAction::WINDOW_HELP,
94
        Visible_true);
95
    // TRANSLATORS: short button name for quests window.
96
    addButton(N_("QE"),
97
        12,
98
        // TRANSLATORS: long button name for quests window.
99
        _("Quests"), x, h, InputAction::WINDOW_QUESTS,
100
        Visible_true);
101
    // TRANSLATORS: short button name for kill stats window.
102
    addButton(N_("KS"),
103
        16,
104
        // TRANSLATORS: long button name for kill stats window.
105
        _("Kill stats"), x, h, InputAction::WINDOW_KILLS,
106
        Visible_true);
107
    addButton(":-)",
108
        6,
109
        // TRANSLATORS: long button name for emotes window.
110
        _("Smilies"), x, h, InputAction::WINDOW_EMOTE_SHORTCUT,
111
        Visible_true);
112
    // TRANSLATORS: short button name for chat window.
113
    addButton(N_("CH"),
114
        20,
115
        // TRANSLATORS: longt button name for chat window.
116
        _("Chat"), x, h, InputAction::WINDOW_CHAT,
117
#ifdef ANDROID
118
        Visible_true);
119
#else  // ANDROID
120
        Visible_false);
121
#endif  // ANDROID
122
123
    // TRANSLATORS: short button name for status window.
124
    addButton(N_("STA"),
125
        17,
126
        // TRANSLATORS: long button name for status window.
127
        _("Status"), x, h, InputAction::WINDOW_STATUS,
128
        Visible_true);
129
    // TRANSLATORS: short button name for equipment window.
130
    addButton(N_("EQU"),
131
        7,
132
        // TRANSLATORS: long button name for equipment window.
133
        _("Equipment"), x, h, InputAction::WINDOW_EQUIPMENT,
134
        Visible_true);
135
    // TRANSLATORS: short button name for inventory window.
136
    addButton(N_("INV"),
137
        9,
138
        // TRANSLATORS: long button name for inventory window.
139
        _("Inventory"), x, h, InputAction::WINDOW_INVENTORY,
140
        Visible_true);
141
    // TRANSLATORS: short button name for cart window.
142
    addButton(N_("CA"),
143
        11,
144
        // TRANSLATORS: long button name for cart window.
145
        _("Cart"), x, h, InputAction::WINDOW_CART,
146
        Visible_true);
147
    // TRANSLATORS: short button name for map window.
148
    addButton(N_("MAP"),
149
        19,
150
        // TRANSLATORS: long button name for map window.
151
        _("Map"), x, h, InputAction::WINDOW_MINIMAP,
152
        Visible_false);
153
154
    if (skillDialog->hasSkills())
155
    {
156
        // TRANSLATORS: short button name for skills window.
157
        addButton(N_("SKI"),
158
            5,
159
            // TRANSLATORS: long button name for skills window.
160
            _("Skills"), x, h, InputAction::WINDOW_SKILL,
161
        Visible_true);
162
    }
163
164
    // TRANSLATORS: short button name for social window.
165
    addButton(N_("SOC"),
166
        1,
167
        // TRANSLATORS: long button name for social window.
168
        _("Social"), x, h, InputAction::WINDOW_SOCIAL,
169
        Visible_true);
170
    // TRANSLATORS: short button name for shortcuts window.
171
    addButton(N_("SH"),
172
        14,
173
        // TRANSLATORS: long button name for shortcuts window.
174
        _("Shortcuts"), x, h, InputAction::WINDOW_SHORTCUT,
175
        Visible_true);
176
    // TRANSLATORS: short button name for spells window.
177
    addButton(N_("SP"),
178
        15,
179
        // TRANSLATORS: long button name for spells window.
180
        _("Spells"), x, h, InputAction::WINDOW_SPELLS,
181
        Visible_true);
182
    // TRANSLATORS: short button name for drops window.
183
    addButton(N_("DR"),
184
        26,
185
        // TRANSLATORS: long button name for drops window.
186
        _("Drop"), x, h, InputAction::WINDOW_DROP,
187
        Visible_false);
188
    // TRANSLATORS: short button name for did you know window.
189
    addButton(N_("YK"),
190
        24,
191
        // TRANSLATORS: long button name for did you know window.
192
        _("Did you know"), x, h, InputAction::WINDOW_DIDYOUKNOW,
193
        Visible_false);
194
    // TRANSLATORS: short button name for shop window.
195
    addButton(N_("SHP"),
196
        18,
197
        // TRANSLATORS: long button name for shop window.
198
        _("Shop"), x, h, InputAction::WINDOW_SHOP,
199
        Visible_false);
200
    // TRANSLATORS: short button name for outfits window.
201
    addButton(N_("OU"),
202
        21,
203
        // TRANSLATORS: long button name for outfits window.
204
        _("Outfits"), x, h, InputAction::WINDOW_OUTFIT,
205
        Visible_false);
206
    // TRANSLATORS: short button name for updates window.
207
    addButton(N_("UP"),
208
        25,
209
        // TRANSLATORS: long button name for updates window.
210
        _("Updates"), x, h, InputAction::WINDOW_UPDATER,
211
        Visible_false);
212
    // TRANSLATORS: short button name for bank window.
213
    addButton(N_("BA"),
214
        2,
215
        // TRANSLATORS: long button name for bank window.
216
        _("Bank"), x, h, InputAction::WINDOW_BANK,
217
        Visible_true);
218
    // TRANSLATORS: short button name for mail window.
219
    addButton(N_("MA"),
220
        10,
221
        // TRANSLATORS: long button name for mail window.
222
        _("Mail"), x, h, InputAction::WINDOW_MAIL,
223
        Visible_true);
224
    // TRANSLATORS: short button name for clan window.
225
    addButton(N_("CL"),
226
        4,
227
        // TRANSLATORS: long button name for clan window.
228
        _("Clan"), x, h, InputAction::WINDOW_CLAN,
229
        Visible_true);
230
    // TRANSLATORS: short button name for server info window.
231
    addButton(N_("SI"),
232
        8,
233
        // TRANSLATORS: long button name for server info window.
234
        _("Server info"), x, h, InputAction::WINDOW_SERVER_INFO,
235
        Visible_true);
236
    // TRANSLATORS: short button name for debug window.
237
    addButton(N_("DBG"),
238
        22,
239
        // TRANSLATORS: long button name for debug window.
240
        _("Debug"), x, h, InputAction::WINDOW_DEBUG,
241
#ifdef ANDROID
242
        Visible_true);
243
#else  // ANDROID
244
        Visible_false);
245
#endif  // ANDROID
246
247
    // TRANSLATORS: short button name for windows list menu.
248
    addButton(N_("WIN"),
249
        23,
250
        // TRANSLATORS: long button name for windows list menu.
251
        _("Windows"), x, h, InputAction::SHOW_WINDOWS,
252
        Visible_false);
253
    // TRANSLATORS: short button name for setup window.
254
    addButton(N_("SET"),
255
        3,
256
        // TRANSLATORS: long button name for setup window.
257
        _("Setup"), x, h, InputAction::WINDOW_SETUP,
258
        Visible_true);
259
260
    x += mPadding - mSpacing;
261
    if (mainGraphics != nullptr)
262
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
263
264
    loadButtons();
265
266
    addMouseListener(this);
267
    setVisible(Visible_true);
268
269
    config.addListener("autohideButtons", this);
270
    mAutoHide = config.getIntValue("autohideButtons");
271
}
272
273
WindowMenu::~WindowMenu()
274
{
275
    config.removeListener("autohideButtons", this);
276
    CHECKLISTENERS
277
278
    for (std::map <std::string, ButtonInfo*>::iterator
279
         it = mButtonNames.begin(),
280
         it_fend = mButtonNames.end(); it != it_fend; ++it)
281
    {
282
        delete (*it).second;
283
    }
284
    mButtonNames.clear();
285
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
286
    {
287
        Button *const btn = *it;
288
        if (btn == nullptr)
289
            continue;
290
        if (btn->mVisible == Visible_false)
291
            delete btn;
292
    }
293
    delete_all(mButtonTexts);
294
    mButtonTexts.clear();
295
    if (mImageSet != nullptr)
296
    {
297
        mImageSet->decRef();
298
        mImageSet = nullptr;
299
    }
300
    if (mSkin != nullptr)
301
    {
302
        if (theme != nullptr)
303
            theme->unload(mSkin);
304
        mSkin = nullptr;
305
    }
306
}
307
308
void WindowMenu::action(const ActionEvent &event)
309
{
310
    const std::string &eventId = event.getId();
311
    const std::map <std::string, ButtonInfo*>::iterator
312
        it = mButtonNames.find(eventId);
313
    if (it == mButtonNames.end())
314
        return;
315
316
    const ButtonInfo *const info = (*it).second;
317
    if (info == nullptr)
318
        return;
319
320
    inputManager.executeAction(info->key);
321
}
322
323
void WindowMenu::addButton(const char *const text,
324
                           const int iconNumber,
325
                           const std::string &description,
326
                           int &restrict x,
327
                           int &restrict h,
328
                           const InputActionT key,
329
                           const Visible visible)
330
{
331
    Button *btn = nullptr;
332
    if (settings.showButtonIcons &&
333
        mImageSet)
334
    {
335
        Image *const image = mImageSet->get(iconNumber);
336
        if (image != nullptr)
337
        {
338
/*
339
            btn = new Button(this,
340
                "buttonsicons.png",
341
                20,
342
                20,
343
                text,
344
                BUTTON_SKIN,
345
                this);
346
*/
347
            btn = new Button(this,
348
                std::string(),
349
                text,
350
                BUTTON_SKIN,
351
                this);
352
            btn->setImage(image);
353
            btn->adjustSize();
354
        }
355
    }
356
    if (btn == nullptr)
357
    {
358
        btn = new Button(this,
359
            gettext(text),
360
            text,
361
            BUTTON_SKIN,
362
            this);
363
    }
364
    btn->setPosition(x, mPadding);
365
    btn->setDescription(description);
366
    btn->setTag(CAST_S32(key));
367
    add(btn);
368
    btn->setFocusable(false);
369
    x += btn->getWidth() + mSpacing;
370
    h = btn->getHeight() + 2 * mPadding;
371
    mButtons.push_back(btn);
372
    mButtonNames[text] = new ButtonInfo(btn, key, visible);
373
    if (key != InputAction::SHOW_WINDOWS)
374
        mButtonTexts.push_back(new ButtonText(description, key));
375
}
376
377
void WindowMenu::mousePressed(MouseEvent &event)
378
{
379
    if (popupManager == nullptr)
380
        return;
381
382
    if (event.getButton() == MouseButton::RIGHT)
383
    {
384
        if (mSmallWindow)
385
            return;
386
387
        event.consume();
388
        Button *const btn = dynamic_cast<Button*>(event.getSource());
389
        if (btn == nullptr)
390
            return;
391
        if (popupMenu != nullptr)
392
        {
393
            popupMenu->showPopup(getX() + event.getX(),
394
                getY() + event.getY(), btn);
395
        }
396
    }
397
}
398
399
void WindowMenu::mouseMoved(MouseEvent &event)
400
{
401
    mHaveMouse = true;
402
403
    if (textPopup == nullptr)
404
        return;
405
406
    if (event.getSource() == this)
407
    {
408
        textPopup->hide();
409
        return;
410
    }
411
412
    const Button *const btn = dynamic_cast<const Button *>(
413
        event.getSource());
414
415
    if (btn == nullptr)
416
    {
417
        textPopup->hide();
418
        return;
419
    }
420
421
    const int x = event.getX();
422
    const int y = event.getY();
423
    const InputActionT key = static_cast<InputActionT>(btn->getTag());
424
    const Rect &rect = mDimension;
425
    if (key != InputAction::NO_VALUE)
426
    {
427
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription(),
428
            // TRANSLATORS: short key name
429
            strprintf(_("Key: %s"), inputManager.getKeyValueString(
430
            key).c_str()));
431
    }
432
    else
433
    {
434
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription());
435
    }
436
}
437
438
void WindowMenu::mouseExited(MouseEvent& event A_UNUSED)
439
{
440
    mHaveMouse = false;
441
    if (textPopup == nullptr)
442
        return;
443
444
    textPopup->hide();
445
}
446
447
void WindowMenu::showButton(const std::string &name,
448
                            const Visible visible)
449
{
450
    const ButtonInfo *const info = mButtonNames[name];
451
    if ((info == nullptr) || (info->button == nullptr))
452
        return;
453
454
    info->button->setVisible(visible);
455
    updateButtons();
456
    saveButtons();
457
}
458
459
void WindowMenu::updateButtons()
460
{
461
    int x = mPadding;
462
    int h = 0;
463
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
464
        safeRemove(*it);
465
    const int pad2 = 2 * mPadding;
466
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
467
    {
468
        Button *const btn = *it;
469
        if (btn == nullptr)
470
            continue;
471
        if (btn->mVisible == Visible_true)
472
        {
473
            btn->setPosition(x, mPadding);
474
            add(btn);
475
            x += btn->getWidth() + mSpacing;
476
            h = btn->getHeight() + pad2;
477
        }
478
    }
479
    x += mPadding - mSpacing;
480
    if (mainGraphics != nullptr)
481
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
482
}
483
484
void WindowMenu::loadButtons()
485
{
486
    if (!mSmallWindow)
487
    {
488
        if (config.getValue("windowmenu0", "").empty())
489
        {
490
            for (std::map <std::string, ButtonInfo*>::iterator
491
                 it = mButtonNames.begin(),
492
                 it_fend = mButtonNames.end(); it != it_fend; ++it)
493
            {
494
                const ButtonInfo *const info = (*it).second;
495
                if (info == nullptr ||
496
                    info->button == nullptr ||
497
                    info->visible == Visible_true)
498
                {
499
                    continue;
500
                }
501
                info->button->setVisible(Visible_false);
502
            }
503
            updateButtons();
504
            return;
505
        }
506
507
        for (int f = 0; f < 30; f ++)
508
        {
509
            const std::string str = config.getValue(
510
                "windowmenu" + toString(f), "");
511
            if (str.empty() || str == "SET")
512
                continue;
513
            const ButtonInfo *const info = mButtonNames[str];
514
            if ((info == nullptr) || (info->button == nullptr))
515
                continue;
516
            info->button->setVisible(Visible_false);
517
        }
518
    }
519
    else
520
    {
521
        for (std::map <std::string, ButtonInfo*>::iterator
522
             it = mButtonNames.begin(),
523
             it_fend = mButtonNames.end(); it != it_fend; ++it)
524
        {
525
            const ButtonInfo *const info = (*it).second;
526
            if ((info == nullptr) || (info->button == nullptr))
527
                continue;
528
            Button *const button = info->button;
529
            const std::string &str = button->getActionEventId();
530
            button->setVisible(fromBool(
531
                str == "SET" || str == "WIN", Visible));
532
        }
533
    }
534
    updateButtons();
535
}
536
537
void WindowMenu::saveButtons() const
538
{
539
    int i = 0;
540
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
541
    {
542
        const Button *const btn = *it;
543
        if ((btn != nullptr) && btn->mVisible == Visible_false)
544
        {
545
            config.setValue("windowmenu" + toString(i),
546
                btn->getActionEventId());
547
            i ++;
548
        }
549
    }
550
    for (int f = i; f < 30; f ++)
551
        config.deleteKey("windowmenu" + toString(f));
552
}
553
554
void WindowMenu::drawChildren(Graphics *const graphics)
555
{
556
    if (mHaveMouse ||
557
        mAutoHide == 0 ||
558
        (mAutoHide == 1 &&
559
        mainGraphics != nullptr &&
560
        (mSmallWindow || mainGraphics->mWidth > 800)))
561
    {
562
        Container::drawChildren(graphics);
563
    }
564
}
565
566
void WindowMenu::safeDrawChildren(Graphics *const graphics)
567
{
568
    if (mHaveMouse ||
569
        mAutoHide == 0 ||
570
        (mAutoHide == 1 &&
571
        mainGraphics != nullptr &&
572
        (mSmallWindow || mainGraphics->mWidth > 800)))
573
    {
574
        Container::safeDrawChildren(graphics);
575
    }
576
}
577
578
void WindowMenu::optionChanged(const std::string &name)
579
{
580
    if (name == "autohideButtons")
581
        mAutoHide = config.getIntValue("autohideButtons");
582

3
}
583
584
#ifdef USE_PROFILER
585
void WindowMenu::logicChildren()
586
{
587
    BLOCK_START("WindowMenu::logicChildren")
588
    BasicContainer::logicChildren();
589
    BLOCK_END("WindowMenu::logicChildren")
590
}
591
#endif  // USE_PROFILER